【笔记】Mybatis高级查询(四)--使用resultMap的<collection>标签实现一对多和多对多查询

<collection>集合的嵌套结果映射就是指通过一次SQL查询将所有的结果查询出来,然后映射到不同的对象中。在一对多的关系中,主表一条数据会对应关联表的多条数据。因此一般查询时会查询出多条结果,按照一对多的数据映射时,最终的结果数会小于等于查询的总记录数。

在RBAC权限系统中一个用户拥有多个角色,一个角色又拥有多个权限。以下例子通过嵌套查询查出某个用户及用户角色。当输入用户编号时为一对多查询,不输入编号时为多对多查询。

1. 在SysUser中加入roles属性,如下:

	/**
     * 用户的角色集合(一个用户可以有多个角色)
     */
    private List<SysRole> roles;

	public List<SysRole> getRoles() {
		return roles;
	}

	public void setRoles(List<SysRole> roles) {
		this.roles = roles;
	}

2. 在SysUserMapper.xml中加入resultMap和selectRolesById,如下:

  <!-- 使用resultMap的<collection>标签进行一对多查询 -->
  <resultMap id="userRolesMap" extends="userMap" type="ex.mybatis.rbac.model.SysUser">
    
    <!-- 角色的集合 -->
    <collection property="roles" columnPrefix="r_" resultMap="ex.mybatis.rbac.mapper.SysRoleMapper.roleMap"/>
  </resultMap>
  
  <!-- 使用resultMap的<collection>标签进行一对多查询 -->
  <select id="selectRolesById" resultMap="userRolesMap">
    select 
	    u.id, 
	    u.user_name, 
	    u.user_password, 
	    u.user_email, 
	    u.create_time, 
	    u.user_info, 
	    u.head_img,
	    r.id r_id, 
	    r.role_name r_role_name, 
	    r.enabled r_enabled, 
	    r.create_by r_create_by, 
	    r.create_time r_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
    <where>
    	<if test="id != null">
    		u.id = #{id}
    	</if>
    </where>
  </select>

3. 在SysUserMapper接口中加入selectRolesById方法,如下:

	/**
     * 使用resultMap的<collection>标签进行一对多查询
     * @param id
     * @return
     */
    List<SysUser> selectRolesById(@Param("id") Long id);

4. 在UserMaperTest中加入selectRolesById测试方法,如下:

	@Test
	public void testSelectRolesById() {
		// 获取SqlSession
		SqlSession sqlSession = openSession();
		try {
			// 获取SysUserMapper接口
			SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
			
			// 调用selectRolesById方法
			List<SysUser> users = userMapper.selectRolesById(1L);
			
			System.out.println("用户数:" + users.size());
			for (SysUser user : users) {
				System.out.println("用户:" + user);
				for (SysRole role : user.getRoles()) {
					System.out.println("--角色:" + role);
				}
				System.out.println();
			}
			
			System.out.println();
		} finally {
			sqlSession.close();
		}
	}

5. 测试结果(id=1L时,为一对多查询)

[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.create_time, u.user_info, u.head_img, r.id r_id, r.role_name r_role_name, r.enabled r_enabled, r.create_by r_create_by, r.create_time r_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 where u.id = ? 
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - ==> Parameters: 1(Long)
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==    Columns: id, user_name, user_password, user_email, create_time, user_info, head_img, r_id, r_role_name, r_enabled, r_create_by, r_create_time
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==        Row: 1, admin, 123456, [email protected], 2018-10-01 18:27:36.0, <<BLOB>>, <<BLOB>>, 1, 管理员, 1, 1, 2018-10-01 18:27:36.0
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==        Row: 1, admin, 123456, [email protected], 2018-10-01 18:27:36.0, <<BLOB>>, <<BLOB>>, 2, 普通用户, 0, 1, 2018-10-01 18:27:37.0
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==      Total: 2

用户:SysUser [id=1, userName=admin, userPassword=123456, [email protected], createTime=Mon Oct 01 18:27:36 CST 2018, userInfo=管理员, headImg=null]
--角色:SysRole [id=1, roleName=管理员, enabled=enabled, createBy=1, createTime=Mon Oct 01 18:27:36 CST 2018]
--角色:SysRole [id=2, roleName=普通用户, enabled=disabled, createBy=1, createTime=Mon Oct 01 18:27:37 CST 2018]

6. 测试结果(id=null时,为多对多查询)

[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.create_time, u.user_info, u.head_img, r.id r_id, r.role_name r_role_name, r.enabled r_enabled, r.create_by r_create_by, r.create_time r_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 
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - ==> Parameters: 
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==    Columns: id, user_name, user_password, user_email, create_time, user_info, head_img, r_id, r_role_name, r_enabled, r_create_by, r_create_time
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==        Row: 1, admin, 123456, [email protected], 2018-10-01 18:27:36.0, <<BLOB>>, <<BLOB>>, 1, 管理员, 1, 1, 2018-10-01 18:27:36.0
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==        Row: 1, admin, 123456, [email protected], 2018-10-01 18:27:36.0, <<BLOB>>, <<BLOB>>, 2, 普通用户, 0, 1, 2018-10-01 18:27:37.0
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==        Row: 1001, test, 123456, [email protected], 2018-10-02 17:17:11.0, <<BLOB>>, <<BLOB>>, 2, 普通用户, 0, 1, 2018-10-01 18:27:37.0
[ex.mybatis.rbac.mapper.SysUserMapper.selectRolesById] - <==      Total: 3
用户数:2
用户:SysUser [id=1, userName=admin, userPassword=123456, [email protected], createTime=Mon Oct 01 18:27:36 CST 2018, userInfo=管理员, headImg=null]
--角色:SysRole [id=1, roleName=管理员, enabled=enabled, createBy=1, createTime=Mon Oct 01 18:27:36 CST 2018]
--角色:SysRole [id=2, roleName=普通用户, enabled=disabled, createBy=1, createTime=Mon Oct 01 18:27:37 CST 2018]

用户:SysUser [id=1001, userName=test, userPassword=123456, [email protected], createTime=Tue Oct 02 17:17:11 CST 2018, userInfo=测试用户, headImg=null]
--角色:SysRole [id=2, roleName=普通用户, enabled=disabled, createBy=1, createTime=Mon Oct 01 18:27:37 CST 2018]

通过日志可以看到,SQL执行的结果数为3条,后面输入的用户数为2,为什么呢?这是Mybatis对结果集进行了合并。

7. Mybatis结果集合并原理

  • Mybatis在处理结果集时,首先会根据resultMap中配置的<id>属性判断结果是否相同,<id>属性相当于表记录的主键,如果<id>相同则认为是相同的记录则合并。如果resultMap没有配置<id>属性,则会把resultMap中配置的所有字段进行比较,如果所有字段都相同则合并。只要有一个不相同都不合并。
  • 因此建议所有resultMap都配置<id>属性以提高查询效率。

猜你喜欢

转载自blog.csdn.net/q283614346/article/details/83246962