Mybatis通过ResultMap实现关联查询

Mybatis通过ResultMap实现关联查询

本文主要讲通过以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;
}

1、通过join进行sql的连接查询

首先写对应的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 selectUserWithAll()方法即可获取到对应的关联查询结果。

2、通过嵌套的select查询实现关联查询

该方法相比其连接查询而言效率更高,同时由于可以自定义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 selectUserWithAll()这样的方法时,会自动执行Group与Mail的select方法,然后通过resultMap映射至UserWithAll实体类中的group与mail中。

3、总结

这两种方法都可以实现表关联查询,区别在于一种关联查询是通过数据库的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表即可。

你可能感兴趣的:(随记)