【笔记】Mybatis高级查询(准备)
【笔记】Mybatis高级查询(一)–使用自动映射处理一对一关系
【笔记】Mybatis高级查询(三)–使用标签实现嵌套查询及延迟加载
【笔记】Mybatis高级查询(四)–使用resultMap的标签实现一对多和多对多查询
【笔记】Mybatis高级查询(五)–使用resultMap的进行嵌套查询及延迟加载
【笔记】Mybatis高级查询(小结)–嵌套查询及延迟加载
【笔记】Mybatis高级查询(六)–鉴别器discrimiator的使用
【笔记】Mybatis高级查询(七)–存储过程调用
【笔记】Mybatis高级查询(八)–枚举处理器的使用
【笔记】Mybatis高级查询(九)–Mybatis代码生成器的使用
【笔记】Mybatis高级查询(十)–Mybatis缓存使用
除了使用Mybatis的自动映射处理一对一嵌套外,还可以在XML映射文件中配置结果映射。以下例子是用resultMap配置来处理上一节一对一映射的。
<!-- 使用resultMap配置一对一映射(原始版) -->
<resultMap id="userRoleMap" type="ex.mybatis.rbac.model.SysUser">
<id column="id" property="id" />
<result column="user_name" property="userName" />
<result column="user_password" property="userPassword" />
<result column="user_email" property="userEmail" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="user_info" property="userInfo" />
<result column="head_img" jdbcType="BLOB" property="headImg" />
<!-- role相关属性,为了避免不同表有相同的列,所有可能重名的都加上前缀r_ -->
<result column="r_id" property="role.id" />
<result column="role_name" property="role.roleName" />
<result column="enabled" property="role.enabled" />
<result column="create_by" property="role.createBy" />
<result column="r_create_time" jdbcType="TIMESTAMP" property="role.createTime" />
</resultMap>
这种配置和上一节相似的地方在于role的property配置部分使用了“role.”前缀。在column部分,为了避免不同表中存在相同的列,所有可能重复的列都加上了r_前缀。使用这种配置时,还需要修改SQL语句。继续在XML中增加selectUserAndRoleById2方法,如下:
<!-- 假设一个用户只有一个角色(使用resultMap配置一对一映射)
注意:resultMap中列为避免重复起的别名,需要与SQL中别名一样,否则结果映射为空
-->
<select id="selectUserAndRoleById2" resultMap="userRoleMap">
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.enabled,
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 = #{id}
</select>
/**
* 假设一个用户只有一个角色(使用resultMap配置一对一映射)
* @param id
* @return
*/
SysUser selectUserAndRoleById2(Long id);
@Test
public void testSelectUserAndRoleById2() {
// 获取SqlSession
SqlSession sqlSession = openSession();
try {
// 获取SysUserMapper接口
SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
// 调用selectUserAndRoleById2方法
SysUser user = userMapper.selectUserAndRoleById2(1001L);
// user不为空
Assert.assertNotNull(user);
System.out.println(user.getRole());
// role不为空
Assert.assertNotNull(user.getRole());
System.out.println();
} finally {
sqlSession.close();
}
}
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById2] - ==> 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.enabled, 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.selectUserAndRoleById2] - ==> Parameters: 1001(Long)
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById2] - <== Columns: id, user_name, user_password, user_email, create_time, user_info, head_img, r_id, role_name, enabled, create_by, r_create_time
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById2] - <== 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.selectUserAndRoleById2] - <== Total: 1
SysRole [id=2, roleName=普通用户, enabled=disabled, createBy=1, createTime=Mon Oct 01 18:27:37 CST 2018]
用过上一种写法后,发现resultMap非常烦琐,不但没有方便使用,反而增加了工作量。为了简化这种烦琐的配置,Mybatis提供了resultMap继承功能。以下例子是用Mybatis的resultMap继承功能简化上面的resultMap配置。因为Mybatis代码生成器会生成一个基本的resultMap,所以直接继承,在SysUserMapper.xml中增加userRoleMap2如下:
<!-- 使用resultMap配置一对一映射(使用resultMap继承配置) -->
<resultMap id="userRoleMap2" extends="userMap" type="ex.mybatis.rbac.model.SysUser">
<!-- role相关属性,为了避免不同表有相同的列,所有可能重名的都加上前缀r_ -->
<result column="r_id" property="role.id" />
<result column="role_name" property="role.roleName" />
<result column="enabled" property="role.enabled" />
<result column="create_by" property="role.createBy" />
<result column="r_create_time" jdbcType="TIMESTAMP" property="role.createTime" />
</resultMap>
使用了继承后配置简单了,而且对主表userMap需要修改时,只改一个地方就可以了。把selectUserAndRoleById2方法的resultMap替换为userRoleMap2,其它地方不用改,测试结果与上面一样,配置如下:
<!-- 假设一个用户只有一个角色(使用resultMap配置一对一映射)
注意:resultMap中列为避免重复起的别名,需要与SQL中别名一样,否则结果映射为空
-->
<select id="selectUserAndRoleById2" resultMap="userRoleMap2">
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.enabled,
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 = #{id}
</select>
在resultMap中,
<association>
标签用于与一个复杂类型进行关联。即用于一对一的关联配置。
<association>
标签的关联配置用到以下属性:
- 在SysUserMapper.xml中增加userRoleMap3
<!-- 使用resultMap的association标签配置一对一映射 -->
<resultMap id="userRoleMap3" extends="userMap" type="ex.mybatis.rbac.model.SysUser">
<!-- role相关属性,前缀都加上了r_ -->
<association property="role" columnPrefix="r_" javaType="ex.mybatis.rbac.model.SysRole">
<result column="id" property="id" />
<result column="role_name" property="roleName" />
<result column="enabled" property="enabled" />
<result column="create_by" property="createBy" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</association>
</resultMap>
- 因为列名全加上了r_前缀,所以要修改SQL,因些增加selectUserAndRoleById3方法,如下:
<!-- 使用resultMap的association标签配置一对一映射 -->
<select id="selectUserAndRoleById3" resultMap="userRoleMap3">
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 = #{id}
</select>
- 在SysUserMapper类增加selectUserAndRoleById3方法,如下:
/**
* 假设一个用户只有一个角色(使用resultMap的association标签配置一对一映射)
* @param id
* @return
*/
SysUser selectUserAndRoleById3(Long id);
- 测试结果
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById3] - ==> 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.selectUserAndRoleById3] - ==> Parameters: 1001(Long)
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById3] - <== 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.selectUserAndRoleById3] - <== 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.selectUserAndRoleById3] - <== Total: 1
SysRole [id=2, roleName=普通用户, enabled=disabled, createBy=1, createTime=Mon Oct 01 18:27:37 CST 2018]
<association>
标签支持直接引用其它地方的resultMap,因些到这里,resultMap还可以再简化。如下为最简版,项目中应当这样用。
<!-- 使用resultMap的association标签配置一对一映射(最简版) -->
<resultMap id="userRoleMap4" extends="userMap" type="ex.mybatis.rbac.model.SysUser">
<!-- role相关属性,直接通过resultMap属性引用roleMap,需要加上命名空间的前缀,列前缀都加上了r_ -->
<association property="role" columnPrefix="r_" resultMap="ex.mybatis.rbac.mapper.SysRoleMapper.roleMap" />
</resultMap>
- 把selectUserAndRoleById3方法的resultMap替换为userRoleMap4,其它地方不用改,测试结果与上面一样。