【笔记】Mybatis高级查询(准备)
【笔记】Mybatis高级查询(一)–使用自动映射处理一对一关系
【笔记】Mybatis高级查询(二)–使用resultMap配置一对一映射
【笔记】Mybatis高级查询(三)–使用标签实现嵌套查询及延迟加载
【笔记】Mybatis高级查询(五)–使用resultMap的进行嵌套查询及延迟加载
【笔记】Mybatis高级查询(小结)–嵌套查询及延迟加载
【笔记】Mybatis高级查询(六)–鉴别器discrimiator的使用
【笔记】Mybatis高级查询(七)–存储过程调用
【笔记】Mybatis高级查询(八)–枚举处理器的使用
【笔记】Mybatis高级查询(九)–Mybatis代码生成器的使用
【笔记】Mybatis高级查询(十)–Mybatis缓存使用
<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, admin@mybatis.ex, 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, admin@mybatis.ex, 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, userEmail=admin@mybatis.ex, 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, admin@mybatis.ex, 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, admin@mybatis.ex, 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, test@mybatis.ex, 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, userEmail=admin@mybatis.ex, 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, userEmail=test@mybatis.ex, 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>
属性以提高查询效率。