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

2021-08-17 11:00:50 浏览数 (1)

文章目录

  • 概述
  • collection集合的嵌套结果映射
    • SysUse实体类改造
    • UserMapper接口增加接口方法
    • UserMapper.xml
    • 单元测试
    • MyBatis的处理规则
    • 两层嵌套
      • PrivilegeMap.xml增加映射
      • SysRole实体类改造
      • RoleMapper.xml文件中增加如下resultMap
      • UserMapper.xml改造
      • 单元测试
  • collection集合的嵌套查询

概述

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


collection集合的嵌套结果映射

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

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

SysUse实体类改造

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

增加

代码语言:javascript复制
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接口增加接口方法

代码语言:javascript复制
/**
	 * 
	 * 
	 * @Title: selectAllUserAndRoles
	 * 
	 * @Description:获取所有用户及对应的角色
	 * 
	 * @return
	 * 
	 * @return: List
	 */
	List<SysUser> selectAllUserAndRoles();

UserMapper.xml

代码语言:javascript复制
	<resultMap id="userRoleListMap" extends="userMap"
			   type="com.artisan.mybatis.xml.domain.SysUser" >
		
		<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


单元测试

代码语言:javascript复制
@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看下数据

点进去一个看下

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

接下来看下日志

代码语言:javascript复制
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标签

代码语言:javascript复制
<id property="id" column="id"  />

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

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

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

代码语言:javascript复制
<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条数据,修改后,再次执行单元测试。

代码语言:javascript复制
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 
代码语言:javascript复制
 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标签.

代码语言:javascript复制
<result property="id" column="id"/>

两层嵌套

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

PrivilegeMap.xml增加映射

代码语言:javascript复制
<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实体类改造

增加

代码语言:javascript复制
	/**
	 * 一对多,权限集合
	 */
	List<SysPrivilege> privilegeList;


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

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

RoleMapper.xml文件中增加如下resultMap

代码语言:javascript复制
<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改造

代码语言:javascript复制
<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进行关联

代码语言:javascript复制
<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如下


单元测试

代码语言:javascript复制
@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("tt权限名:"   sysPrivilege.getPrivilegeName());
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			sqlSession.close();
			logger.info("sqlSession close successfully ");
		}
	}

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


日志

代码语言:javascript复制
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查询。 后续单开篇介绍。

0 人点赞