本文主要讲通过以resultmap为主实现mybatis一对一、一对多的关联查询的两种方式。
用户类(User)与用户组别类(Group),关系为一对一。
用户类(User)与邮件类(Mail),关系为一对多。
即每个用户有一个自己归属的组别,同时这个用户手里也有多条接收到的邮件。
User{
private Long userId;
private String userName;
private String userPass;
private Long groupId;
}
Group{
private Long groupId;
private String groupName;
}
Mail{
private Long mailId;
private Long userId; //邮件通过userId来进行关联查询
private String recipient;
private String sender;
private String detail;
}
首先写对应的select查询语句,以左连接的方式查询出对应的Group信息和Mail信息
<select id="selectUserWithAll" resultMap="UserWithAll">
select u.*,g.*,m.* from User u
left join Group g on g.groupId = u.groupId
left join Mail m on m.user = u.userId
where u.userId = #{userId}
select>
于是在执行该方法时,mybatis会依照该sql语句查询出对应的用户的用户信息、组别信息和邮件信息,并将该信息存入UserWithAll这个resultMap指向的实体类。为了接收这些信息,需要新建一个实体类UserWithAll,内容如下
UserWithAll extends User{
private Group group;
private List mail;
}
在有了对应的储存位置后,配置resultMap的映射关系,其映射关系为将select查询结果映射至UserWithAll这个实体类中,具体如下。
<resultMap id="UserWtihAll" type="com.test.model.entity.UserWithAll">
<id property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="userPass" column="user_pass"/>
<result property="groupID" column="group_id"/>
<association property="group" javaType="com.test.model.entity.Group"
resultMap="com.test.repository.mybatis.UserMapper.Group"/>
<collection property="mail" javaType="com.test.model.entity.Mail"
resultMap="com.test.repository.mybatis.UserMapper.Mail"/>
resultMap>
在上面的配置中,association和collection分别对应一对一查询和一对多查询,这两个对应新的resultMap来实现相应的映射,要注意的是association不能接收多条数据,否则会报错。下面分别对这两个来写映射关系。
<resultMap id="group" type="com.test.model.entity.Group">
<id property="groupId" column="group_id"/>
<result property="groupName" column="group_name"/>
resultMap>
<resultMap id="mail" type="com.test.model.entity.Mail">
<id property="userId" column="user_id"/>
<result property="mailId" column="mail_id"/>
<result property="recipient" column="recipient"/>
<result property="sender" column="sender"/>
<result property="detail" column="detail"/>
resultMap>
在完成以上内容后,在DAO层用List
方法即可获取到对应的关联查询结果。
该方法相比其连接查询而言效率更高,同时由于可以自定义select查询,比起连接查询也要更灵活一些。首先依旧是先配置UserWithAll的resultMap,区别在于
这两个标签,需要配置这两个要执行的select方法以及传入的参数名,具体如下。
<resultMap id="UserWtihAll" type="com.test.model.entity.UserWithAll">
<id property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="userPass" column="user_pass"/>
<result property="groupID" column="group_id"/>
<association property="group" column="group_id"
select="com.test.repository.mybatis.UserMapper.selectGroupById"/>
<collection property="mail" column="user_id"
select="com.test.repository.mybatis.UserMapper.selectMailByUserId"/>
resultMap>
这里
中的property指的是返回到UserWithAll时对应的属性,column指的是将数据库中哪个字段传入该select方法,select指的是调用哪里的select方法,这里select的路径也可以改为其他Mapper文件里的select方法,比如说是你的参数表映射文件ParamMapper,那么这里的为select="com.test.repository.mybatis.ParamMapper.selectMailByUserId
。在完成这部分后在写对应的select方法及对应的resultMap,如
"group" type="com.test.model.entity.Group">
property="groupId" column="group_id"/>
property="groupName" column="group_name"/>
<select id="selectGroupById" resultMap="Group">
select * from Group where group_id=#{group_id}
select>
同样的Mail的resultMap与select也跟这个一样,不再赘述。经过以上配置后,在执行相应的如List
这样的方法时,会自动执行Group与Mail的select方法,然后通过resultMap映射至UserWithAll实体类中的group与mail中。
这两种方法都可以实现表关联查询,区别在于一种关联查询是通过数据库的sql语句直接获取相应的信息,另一种则是通过resultMap先执行关联的查询,将结果映射回本身的resultMap。两者比较起来的话,前者书写简单,只要配一个resultMap以及在select里加上left join一类的关键字就可以,但执行效率不高,特别是在没有给外键建立索引且数据量较大的情况下,这种方法耗费时长可以说是令人发指。后者书写要稍微麻烦一点,一个是除了要配置resultMap外,还要单独写一份sql语句,但是效率要远高于前者。所以如果是小量数据的关联查询用left join无可厚非,如果数据量大的话尽量使用后者这种方式。顺带一提这两个方式也是可以结合使用的,比如A、B、C三张表关联查询,其中AB数据量较大,C只是A表的一张参数表,那么可以给A和B使用后者那种方法,以A为基础建立resultMap,加入
或者
进行关联的查询,然后在这个resultMap里加一个
指向C的resultMap,在查询语句里left join C表即可。