学习自MyBatis从入门到精通
- 嵌套查询,会执行额外的SQL语句
团队网站的结构关系我是做成了机构用户角色菜单三层嵌套查询,今天一天进行了实现,遇到的错误真的很多
我们知道association/collection关联的嵌套查询这种方式会执行额外外的SQL查询,映射配置会简单很多。
以实现机构-用户-角色-菜单三级嵌套查询为目标,实现嵌套查询
下面以自下而上的过程来实现一个两层嵌套的功能,并且这个自下而上的过程中,每一个方法都是独立可用的方法,最后结果都是以前一个对象为基础。把所有对象设置成延时加载,因此每个方法都可以作为普通(没有嵌套)的查询存在。
- 首先在SysMenuMapper.xml中添加如下方法(角色-菜单嵌套查询)
<select id="selectByRoleId" parameterType="Long" resultMap="BaseResultMap">
select
sm.id, sm.parent_id, sm.name, sm.perms, sm.create_by, sm.del_flag
from sys_menu sm
inner join sys_role_menu srm
on sm.id = srm.menu_id
where srm.role_id = #{roleId}
</select>
这个方法通过角色ID获取角色对应的所有菜单信息,可以在SysMenuMapper接口上增加相应的方法。这是一个很常见的方法,许多时候都需要这样一个方法来获取角色包含的所有权限信息。
- 下一步,在SysRoleMapper.xml中配置映射对应的查询方法,代码如下
1.映射结果
<resultMap id="roleMenuListMapSelect" extends="BaseResultMap" type="cn.hcnet2006.blog.hcnetwebsite.bean.SysRole">
<collection property="menuList"
fetchType="lazy"
column="{roleId=id}"
select="cn.hcnet2006.blog.hcnetwebsite.mapper.SysMenuMapper.selectByRoleId"
/>
</resultMap>
2.本层使用嵌套查询具体查询语句
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="roleMenuListMapSelect">
select id, name, remark, create_by, create_time, last_update_time, last_update_by,
del_flag
from sys_role
where id = #{id,jdbcType=BIGINT}
</select>
在上面的代码中注意column属性配置的{roleId=id}, roleId是select指定方法selectByRoleId中查询的参数,id是当前查询selectUserAndRoleList中查询的角色ID. selectUserAndRoleList只是一个只有一层的一对多映射设置,通过调用sysMenuMapper的seelctByRoleId方法,很轻易就实现了嵌套查询的功能。
-接下来是用户信息了,在SysUserMapper.xml中配置如下映射和查询,代码如下:
1.映射结果
<resultMap id="userRoleMap" type="cn.hcnet2006.blog.hcnetwebsite.bean.SysUser" extends="BaseResultMap">
<collection property="roleList"
fetchType="lazy"
column="{userId=id}"
select="cn.hcnet2006.blog.hcnetwebsite.mapper.SysRoleMapper.selectUserAndRoleList"/>
</resultMap>
2.SysRoleMpper.xml中的方法
<select id="selectUserAndRoleList" resultMap="roleMenuListMapSelect">
select
sr.id, sr.name, sr.remark, sr.create_by, sr.create_time, sr.last_update_time, sr.last_update_by, sr.del_flag
from sys_role sr
inner join sys_user_role sur
on sr.id = sur.role_id
where sur.user_id = #{userId}
</select>
3.具体查询语句
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="userRoleMap">
select id, name, password, avator, grade, email, mobile, dept_id, (select name from sys_dept d where d.id = sys_user.dept_id) deptZh,create_by, create_time,
last_update_time, last_update_by, del_flag
from sys_user
where id = #{id,jdbcType=BIGINT}
</select>
-终于到了最顶层的机构信息接口了
1.SysUserMapper.xml中的方法
<select id="findByDeptId" resultMap="userRoleMap">
select
id, name, password, avator, grade, email, mobile, dept_id, create_by, create_time, last_update_time, last_update_by, del_flag
from sys_user where dept_id = #{deptId}
</select>
2.结果映射语句
<resultMap id="deptUserMap" type="cn.hcnet2006.blog.hcnetwebsite.bean.SysDept" extends="BaseResultMap">
<collection property="userList"
fetchType="lazy"
column="{deptId=id}"
select="cn.hcnet2006.blog.hcnetwebsite.mapper.SysUserMapper.findByDeptId"/>
</resultMap>
3.具体查询语句
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="deptUserMap">
select id, name, dept_logo, parent_id, create_by, create_time, last_update_time,
last_update_by, del_flag
from sys_dept
where id = #{id,jdbcType=BIGINT}
</select>
-结果
这里我因为调整映射结果wei设置的嵌套映射结果,所以一共三层映射
{
"code": 200,
"msg": null,
"data": {
[
{
"id": 15,
"name": "liubei",
"password": "$2a$10$msaVKbkxkN4lPzUM1I1Iy.RAPCF7pmjt.OmW5sY5zKOXLzPNasS9S",
"avator": "http://hcnet2006-file-apk.oss-cn-shenzhen.aliyuncs.com/liubei.jpg",
"grade": "1",
"email": "1",
"mobile": "11",
"deptId": 1,
"deptZh": null,
"createBy": "1",
"createTime": "2020-03-05",
"lastUpdateTime": "2020-03-05",
"lastUpdateBy": "1",
"delFlag": 0,
"roleList": [
{
"id": 8,
"name": "user2",
"remark": "shiyanb",
"createBy": "ldy",
"createTime": "2020-03-06T11:09:52.000+0000",
"lastUpdateTime": "2020-03-06T11:09:52.000+0000",
"lastUpdateBy": "ldy",
"delFlag": 0,
"menuList": [
{
"id": 1,
"parentId": 2,
"name": "string",
"perms": "ROLE_USER",
"createBy": "string",
"createTime": null,
"lastUpdateTime": null,
"lastUpdateBy": null,
"delFlag": -1
}
]
}
]
},
{
"id": 17,
"name": "liubei1",
"password": "$2a$10$fmmLwCZKvzOuY/e4FDM7oOwPoh0O10p5GE02qorvWhb8W4Lejhe3q",
"avator": "http://hcnet2006-file-apk.oss-cn-shenzhen.aliyuncs.com/liubei1.jpg",
"grade": "1",
"email": "1",
"mobile": "11",
"deptId": 1,
"deptZh": null,
"createBy": "1",
"createTime": "2020-03-05",
"lastUpdateTime": "2020-03-05",
"lastUpdateBy": "1",
"delFlag": 0,
"roleList": []
}
]
}
}
- 书上原话
特被咬注意,之所以能够根据需要查询数据,除了和fetchType设置为false有关,还和全局的aggressiveLazyLoading属性有关,这个属性在介绍association时被设置成了false,所以才会起到按需加载的作用
通过上面的学习,大家应该对collection的用法有了一定的掌握,熟练掌握association和collection的配置,在某些情况下会给我们带来很大的便利
这里附上全局aggressiveLazyLoading的设置方法
mybatis: #Mybaytis映射文件位置
configuration:
aggressive-lazy-loading: false #当参数设置为false时,对任意延迟属性的调用都将按需加载
- bug
在Spring Boot中这个懒加载时不管用的,但是JSON转换失败的错误照常爆出
解决方法在其他的博客中