MyBatis-21MyBatis高级结果映射【一对多映射(2种方式)】

概述

MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】中我们介绍了4种方式实现一对一映射,本篇博文,一对多映射只有两种配置方式,都是使用collection标签进行的。


collection集合的嵌套结果映射

和association类似,集合的嵌套结果映射就是通过一次SQL查询将所有的结果查询出来,然后通过配置的结果映射,将数据映射到不同的对象中取。 在一对多的关系中,主表的一条数据会对应关联表中的多条数据,因此一般查询时会查询出多个结果,按照一对多的数据结果存储数据的时候,最终的结果会小于等于查询的总记录数。

在RBAC权限系统中,一个用户用于多个角色(在使用association是设定的特例,现在一个用户只能有一个角色),每个角色又是多个权限的集合,所以要渐进式的去实现一个SQL,查询出所有用户和用户拥有的角色,以及角色所包含的所有权限信息的两层嵌套结果。

SysUse实体类改造

为了能够存储一对多的数据,先对SysUser类进行修改

增加

public class SysUser{

    // 原有属性, setter getter保持不变 

    /**
     * 用户角色: 一个用户拥有多个角色 , 一对多
     */
    private List<SysRole>  roleList;



    public List<SysRole> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<SysRole> roleList) {
        this.roleList = roleList;
    }


}

UserMapper接口增加接口方法

/**
     * 
     * 
     * @Title: selectAllUserAndRoles
     * 
     * @Description:获取所有用户及对应的角色
     * 
     * @return
     * 
     * @return: List<SysUser>
     */
    List<SysUser> selectAllUserAndRoles();

UserMapper.xml

<!-- 简化的配置 -->
    <resultMap id="userRoleListMap" extends="userMap"
               type="com.artisan.mybatis.xml.domain.SysUser" >
        <!-- sysRole相关的属性   property 对应实体类List<SysRole>属性名-->
        <collection property="roleList" columnPrefix="sysRole_"
            resultMap="roleMap">
        </collection>
    </resultMap>


<select id="selectAllUserAndRoles" resultMap="userRoleListMap">
        SELECT
            u.id,
            u.user_name ,
            u.user_password ,
            u.user_email ,
            u.user_info ,
            u.create_time ,
            u.head_img ,
            r.id sysRole_id,
            r.role_name sysRole_role_name,
            r.enabled sysRole_enabled,
            r.create_by sysRole_create_by,
            r.create_time sysRole_create_time
        FROM
            sys_user u
        INNER JOIN sys_user_role ur ON u.id = ur.user_id
        INNER JOIN sys_role r ON ur.role_id = r.id
    </select>

和一对一映射相比,一对多的userRoleListMap,就是把association改成collection, 然后将property设置为roleList,其他的属性保持不变。

collection用于配置一对多的关系,对应的属性必须是对象中的集合类型,因此这里是roleList。 另外resultMap只是为了配置数据库字段和实体属性的映射关系,因此其他都一样。 同时能存储一对多的数据结构肯定也能存储一对一的关系,所以一对一是一对多的一种特例。 collection支持的属性以及属性的作用和association完全相同。

为了简化配置,我们通过继承userMap来使用sys_user的映射关系,同时我们在UserMapper.xml中配置了roleMap的映射关系(更加合适的问题应该在RoleMapper.xml中,如果在RoleMapper.xml中,引用的时候一定要加上命名空间),因此直接饮用roleMap ,经过这两个方式的简化,最终的userRoleListMap如上

总结下:一对多配置变化的地方是 association变为collection, property由role变为了roleList


单元测试

@Test
    public void selectAllUserAndRolesTest() {
        logger.info("selectAllUserAndRolesTest");
        // 获取SqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            // 获取UserMapper接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用selectAll,查询全部用户
            List<SysUser> userList = userMapper.selectAllUserAndRoles();
            // 结果不为空
            Assert.assertNotNull(userList);
            // 结果大于0
            Assert.assertTrue(userList.size() > 0);

            logger.info("userList总数为:" + userList.size());
            for (SysUser sysUser : userList) {
                logger.info("用户名:" + sysUser.getUserName());
                for (SysRole sysRole : sysUser.getRoleList()) {
                    logger.info("\t角色名:" + sysRole.getRoleName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }

我们在 Assert.assertNotNull(userList); 加上个断点,debug看下数据

这里写图片描述

点进去一个看下

这里写图片描述

从上图可以看到一个用于已经拥有两个角色,实现了一对多的查询。

接下来看下日志

2018-05-02 02:02:26,338  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-05-02 02:02:26,343  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-05-02 02:02:26,346  INFO [main] (UserMapperTest.java:1133) - selectAllUserAndRolesTest
2018-05-02 02:02:26,415 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id 
2018-05-02 02:02:26,538 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 
2018-05-02 02:02:26,586 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time
2018-05-02 02:02:26,587 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 02:02:26,598 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 02:02:26,600 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 02:02:26,602 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 3
2018-05-02 02:02:26,604  INFO [main] (UserMapperTest.java:1146) - userList总数为:2
2018-05-02 02:02:26,604  INFO [main] (UserMapperTest.java:1148) - 用户名:admin
2018-05-02 02:02:26,604  INFO [main] (UserMapperTest.java:1150) -   角色名:管理员
2018-05-02 02:02:26,605  INFO [main] (UserMapperTest.java:1150) -   角色名:普通用户
2018-05-02 02:02:26,605  INFO [main] (UserMapperTest.java:1148) - 用户名:artisan
2018-05-02 02:02:26,605  INFO [main] (UserMapperTest.java:1150) -   角色名:普通用户
2018-05-02 02:02:26,608  INFO [main] (UserMapperTest.java:1157) - sqlSession close successfully 

MyBatis的处理规则

通过日志可以清楚地看到,SQL执行的结果数有3条,用户输出的数量确实2条,也就是说本来查询出的3条结果经过MyBatis对collection数据的处理后,变成了2条。

从日志中,我们知道第一个用户拥有两个角色,所以转换为一对多的数据结构后就变成了两套结果,那么 MyBatis又是怎么知道要处理成这样的结果呢?

先来看MyBatis是如何要知道合并admin的两条数据的,为什么不把test这条数据也合并进去呢?

MyBatis在处理结果的时候,会判断结果是否相同,如果是相同的结果,则只会保留第一个结果。 所以这个问题的关键点就是MyBatis是如何判断结果是否相同。 最简单的情况就是在映射配置中至少有一个id标签

<id property="id" column="id"  />

我们对id的理解一般是,它配置的字段为表的主键(联合主键时可以配置多个id标签),因为MyBatis的resultMap只用于配置结果如何映射,并不知道这个表具体如何。 id的唯一作用就是在嵌套的映射配置中判断数据是否相同。 .当配置id标签时,MyBatis只需要逐条比较所有数据中id标签的字段值是否相同即可。 在配置嵌套结果查询时,配置id标签提高处理效率。

这样一来,上面的查询就不难理解了,因为前两套数据的userMap部分的id相同,所以他们属于同一个用户,因子这条数据会合并到同一个用户中。

为了更加清楚的理解id的作用,我们队userMap的映射进行如下修改。

<resultMap id="userMap" 
               type="com.artisan.mybatis.xml.domain.SysUser">
        <id property="userPassword" column="userPassword"  />
        <result property="userName" column="user_name" />
        <result property="userPassword" column="user_password" />
        <result property="userEmail" column="user_email" />
        <result property="userInfo" column="user_info" />
        <result property="headImg" column="head_img" jdbcType="BLOB" />
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP" />
    </resultMap>

在测试数据中,用户的密码均为 123456

这里写图片描述

如果把密码最为id,按照上面的逻辑,3条数据就会合并为1条数据,修改后,再次执行单元测试。

2018-05-02 12:24:27,161  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-05-02 12:24:27,161  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-05-02 12:24:27,173  INFO [main] (UserMapperTest.java:1133) - selectAllUserAndRolesTest
2018-05-02 12:24:27,253 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id 
2018-05-02 12:24:27,383 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 
2018-05-02 12:24:27,433 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time
2018-05-02 12:24:27,433 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 12:24:27,443 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 12:24:27,443 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 12:24:27,443 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 3
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1146) - userList总数为:1
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1148) - 用户名:admin
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1150) -   角色名:管理员
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1150) -   角色名:普通用户
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1157) - sqlSession close successfully 
 userList总数为:1
 用户名:admin
    角色名:管理员
    角色名:普通用户

用户信心保留的是第一条数据的信心,因此用户名是admin . 角色为什么不是3个呢? 因为“普通用户”这个角色重复了,所以也只保留第一个出现的“普通用户”。 因为MyBatis会对嵌套查询的每一级对象都进行属性比较。 MyBatis会首先比较顶层的对象,如果SysUser相同,就继续比较SysRole部分,如果SysRole不同,就会增加一个sysRole,两个SysROle相同就保留前一个。 假设SysRole还有下一级,仍然按照该规则去比较。

通过上述这个例子应该明白了id的作用了,需要注意的是,很肯能出现一种没有配置id的情况。 当没有配置id的时候,MyBatis就会把resultMap中配置的说哟字段进行比较,如果所有字段的值都相同就合并,只要有一个字段值不同,就不合并。

在嵌套结果配置id属性时,如果查询中没有查询id属性配置的列,就会导致id对应的值为null.这种情况下,所有的id都相同,因此会使嵌套的集合中只有一条数据。 所以在配置id列时,查询语句中必须包含该列。

可以对userMap再次改造,将id标签改为result标签,执行结果是一样的,由于MyBatis要对所有字段字段进行比较,因此当字段数为M时,如果查询结果有N条,就需要进行M*N,相比配置id时的N次比较,效率差很多。 所以尽量配置id标签.

<result property="id" column="id"/>

两层嵌套

在RBAC权限系统中,除了一个用户对应多个角色外,每个角色还会对应多个权限,在上个例子的基础上我们增加一级,获取角色对应的所有权限。

PrivilegeMap.xml增加映射

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
                    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<!-- 当Mapper接口和XML文件关联的时候, namespace的值就需要配置成接口的全限定名称 -->
<mapper namespace="com.artisan.mybatis.xml.mapper.PrivilegeMapper">
    <resultMap id="privilegeMap" type="com.artisan.mybatis.xml.domain.SysPrivilege">
        <id property="id" column="id" />
        <result property="privilegeName" column="privilege_name" />
        <result property="privilegeUrl" column="privilege_url" />
    </resultMap>
</mapper>                           

SysRole实体类改造

增加

    /**
     * 一对多,权限集合
     */
    List<SysPrivilege> privilegeList;


    public List<SysPrivilege> getPrivilegeList() {
        return privilegeList;
    }

    public void setPrivilegeList(List<SysPrivilege> privilegeList) {
        this.privilegeList = privilegeList;
    }

RoleMapper.xml文件中增加如下resultMap

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
                    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!-- 当Mapper接口和XML文件关联的时候, namespace的值就需要配置成接口的全限定名称 -->
<mapper namespace="com.artisan.mybatis.xml.mapper.RoleMapper">
    <resultMap id="rolePrivilegeListMap" 
        type="com.artisan.mybatis.xml.domain.SysRole"
        extends="com.artisan.mybatis.xml.mapper.UserMapper.roleMap">
        <collection property="privilegeList" columnPrefix="privilege_"
            resultMap="com.artisan.mybatis.xml.mapper.PrivilegeMapper.privilegeMap" />
    </resultMap>
</mapper>   

我们创建了角色权限映射,继承了roleMap,嵌套了privilegeList属性,直接使用PrivilegeMapper.xml中的privilegeMap。

UserMapper.xml改造

<resultMap id="userRoleAndPrivilegeListMap" extends="userMap"
               type="com.artisan.mybatis.xml.domain.SysUser" >
        <collection property="roleList" columnPrefix="sysRole_"
            resultMap="com.artisan.mybatis.xml.mapper.RoleMapper.rolePrivilegeListMap">
        </collection>
    </resultMap>

到这里我们就配置好了一个两层嵌套的映射,为了得到权限信息,还需要修改SQL进行关联

<select id="selectAllUserAndRolesAndPrivileges" resultMap="userRoleAndPrivilegeListMap">
        select 
            u.id, 
            u.user_name, 
            u.user_password,
            u.user_email,
            u.user_info,
            u.head_img,
            u.create_time,
            r.id sysRole_id,
            r.role_name sysRole_role_name, 
            r.enabled sysRole_enabled,
            r.create_by sysRole_create_by,
            r.create_time sysRole_create_time,
            p.id sysRole_privilege_id,
            p.privilege_name sysRole_privilege_privilege_name,
            p.privilege_url sysRole_privilege_privilege_url
        from sys_user u
        inner join sys_user_role ur on u.id = ur.user_id
        inner join sys_role r on ur.role_id = r.id
        inner join sys_role_privilege rp on rp.role_id = r.id
        inner join sys_privilege p on p.id = rp.privilege_id
    </select>

这里需要特别注意sys_privilege表中的别名。因为sys_privilege嵌套在rolePrivilegeListMap中,前缀名是 privilege_

这里写图片描述

这里写图片描述

而rolePrivilegeListMap的前缀是sysRole_

这里写图片描述

所以rolePrivilegeListMap中的privilegeMap的前缀就变测过了 sysRole_privilege_

在嵌套中,这个前缀需要叠加,一定不要写错,所以SQL如下

这里写图片描述


单元测试

@Test
    public void selectAllUserAndRolesAndPrivilegesTest() {
        logger.info("selectAllUserAndRolesAndPrivilegesTest");
        // 获取SqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            // 获取UserMapper接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用selectAll,查询全部用户
            List<SysUser> userList = userMapper.selectAllUserAndRolesAndPrivileges();
            // 结果不为空
            Assert.assertNotNull(userList);
            // 结果大于0
            Assert.assertTrue(userList.size() > 0);

            logger.info("userList总数为:" + userList.size());
            for (SysUser sysUser : userList) {
                logger.info("用户名:" + sysUser.getUserName());
                for (SysRole sysRole : sysUser.getRoleList()) {
                    logger.info("\t角色名:" + sysRole.getRoleName());
                    for (SysPrivilege sysPrivilege : sysRole.getPrivilegeList()) {
                        logger.info("\t\t权限名:" + sysPrivilege.getPrivilegeName());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }

Assert.assertNotNull(userList); 加个断点,debug看下数据

这里写图片描述


日志

2018-05-02 20:10:08,202  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-05-02 20:10:08,207  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-05-02 20:10:08,211  INFO [main] (UserMapperTest.java:1164) - selectAllUserAndRolesAndPrivilegesTest
2018-05-02 20:10:08,287 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.user_info, u.head_img, u.create_time, r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time, p.id sysRole_privilege_id, p.privilege_name sysRole_privilege_privilege_name, p.privilege_url sysRole_privilege_privilege_url from sys_user u inner join sys_user_role ur on u.id = ur.user_id inner join sys_role r on ur.role_id = r.id inner join sys_role_privilege rp on rp.role_id = r.id inner join sys_privilege p on p.id = rp.privilege_id 
2018-05-02 20:10:08,411 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 
2018-05-02 20:10:08,448 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time, sysRole_privilege_id, sysRole_privilege_privilege_name, sysRole_privilege_privilege_url
2018-05-02 20:10:08,449 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0, 1, 用户管理, /users
2018-05-02 20:10:08,466 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0, 3, 系统日志, /logs
2018-05-02 20:10:08,468 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0, 2, 角色管理, /roles
2018-05-02 20:10:08,469 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 4, 人员维护, /persons
2018-05-02 20:10:08,473 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 5, 单位维护, /companies
2018-05-02 20:10:08,475 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 4, 人员维护, /persons
2018-05-02 20:10:08,477 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 5, 单位维护, /companies
2018-05-02 20:10:08,478 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 7
2018-05-02 20:10:08,479  INFO [main] (UserMapperTest.java:1177) - userList总数为:2
2018-05-02 20:10:08,479  INFO [main] (UserMapperTest.java:1179) - 用户名:admin
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1181) -   角色名:管理员
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1183) -       权限名:用户管理
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1183) -       权限名:系统日志
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1183) -       权限名:角色管理
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1181) -   角色名:普通用户
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1183) -       权限名:人员维护
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1183) -       权限名:单位维护
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1179) - 用户名:artisan
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1181) -   角色名:普通用户
2018-05-02 20:10:08,484  INFO [main] (UserMapperTest.java:1183) -       权限名:人员维护
2018-05-02 20:10:08,484  INFO [main] (UserMapperTest.java:1183) -       权限名:单位维护
2018-05-02 20:10:08,485  INFO [main] (UserMapperTest.java:1191) - sqlSession close successfully 

collection集合的嵌套查询

同association关联的嵌套查询这种方式类似,collection也会执行额外的SQL查询。 后续单开篇介绍。

猜你喜欢

转载自blog.csdn.net/yangshangwei/article/details/80164922
今日推荐