Mybatis关联查询<association> 和 <collection>
一、背景
1.在系统中一个用户存在多个角色,那么如何在查询用户的信息时同时把他的角色信息查询出来啦?
2.用户pojo:
public class SysUser {
private Long id;
private String userName;
private String password;
private String nickName;
private String salt;
private List<SysRole> roleList;
3.数据库

二、实现
如果一个对象中的属性是另个对象,就会出现对象与对象的中的关系,及是一对一,多对多,还是一对多等等,从上面的需求中如果从user出发来分析,那么一个用户可以有多个对象,那么就存在了一对多的关系,可以直接使用 mybatis的中的collection标签;
如果是一对一的关系的话可以使用association标签,使用方式大相径庭。
<resultMap id="RoleBaseResultMap" type="com.layman.study.mybatis.pojo.SysRole">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="role_name" property="roleName" jdbcType="VARCHAR"/>
<result column="role_code" property="roleCode" jdbcType="VARCHAR"/>
<result column="status" property="status" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap> <resultMap id="UserBaseResultMap" type="com.layman.study.mybatis.pojo.SysUser">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
<result column="nick_name" property="nickName" jdbcType="VARCHAR"/>
<result column="salt" property="salt" jdbcType="VARCHAR"/>
<collection column="id" property="roleList" javaType="list" select="selectSysRoleByUserId"/>
</resultMap> <select id="selectSysUserAll" resultMap="UserBaseResultMap">
SELECT * FROM sys_user
</select> <select id="selectSysUserByPrimaryKey" parameterType="int" resultMap="UserBaseResultMap">
SELECT * FROM sys_user WHERE id = #{id}
</select> <select id="selectSysRoleByUserId" parameterType="int" resultMap="RoleBaseResultMap">
select * from sys_role sr join sys_user_role sur on sr.id = sur.role_id WHERE sur.user_id = #{user_id};
</select>
在上面的场景下解释collection标签:
<collection column="id" property="roleList" javaType="list" select="selectSysRoleByUserId"/>
1.column:是指定需要使用那个字段的值去查询关联的角色信息,这里是使用id,就是用户id,对应查询接口selectSysUserAll中的语句SELECT * FROM sys_user

2.property:这个属性的值就是我们user对象中的roleList字段属性,用来封装查询出来的角色信息
3.javaType:指定property指定的属性在java中的类型
4.select:指定使用按个查询语句去查询角色信息
三、测试
@Test
public void test2() throws Exception {
List<SysUser> userList = sysUserService.selectSysUserAll();
LOGGER.info(objectMapper.writeValueAsString(userList));
}
结果:
[
{
"id": 1,
"userName": "Layman",
"password": "737b0be0e65ddbc20664b377a003c7bd",
"nickName": "聖殿罗刹",
"salt": "SWLwSE",
"roleList": [
{
"id": 1,
"roleName": "超级管理员",
"roleCode": "ADMIN",
"status": 1,
"createTime": 1479889105000
},
{
"id": 2,
"roleName": "普通管理员",
"roleCode": "GENERAL_MANAGER",
"status": 1,
"createTime": 1479889154000
}
]
},
{
"id": 2,
"userName": "leo",
"password": "412a104c131e929751242998542159ab",
"nickName": "爱婷",
"salt": "MUffQ/TBU+V98iBHD0XPwg==",
"roleList": [
{
"id": 2,
"roleName": "普通管理员",
"roleCode": "GENERAL_MANAGER",
"status": 1,
"createTime": 1479889154000
}
]
}
]
引出(N+1的问题):我们通过DEBUG方式查看打出的日志发现,mybatis其实发出了多条查询语句去查询,查询出一个用户然后拿着这个用户的id去查询对应的角色信息
17-02-16 16:55:19,477 [main] DEBUG transaction.SpringManagedTransaction - JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@62ee45c0] will not be managed by Spring
2017-02-16 16:55:19,495 [main] DEBUG SysUserDao.selectSysUserAll - ==> Preparing: SELECT * FROM sys_user
2017-02-16 16:55:19,569 [main] DEBUG SysUserDao.selectSysUserAll - ==> Parameters:
2017-02-16 16:55:19,595 [main] DEBUG SysUserDao.selectSysRoleByUserId - ====> Preparing: select * from sys_role sr join sys_user_role sur on sr.id = sur.role_id WHERE sur.user_id = ?;
2017-02-16 16:55:19,596 [main] DEBUG SysUserDao.selectSysRoleByUserId - ====> Parameters: 1(Integer)
2017-02-16 16:55:19,599 [main] DEBUG SysUserDao.selectSysRoleByUserId - <==== Total: 2
2017-02-16 16:55:19,606 [main] DEBUG SysUserDao.selectSysRoleByUserId - ====> Preparing: select * from sys_role sr join sys_user_role sur on sr.id = sur.role_id WHERE sur.user_id = ?;
2017-02-16 16:55:19,606 [main] DEBUG SysUserDao.selectSysRoleByUserId - ====> Parameters: 2(Integer)
2017-02-16 16:55:19,608 [main] DEBUG SysUserDao.selectSysRoleByUserId - <==== Total: 1
2017-02-16 16:55:19,609 [main] DEBUG SysUserDao.selectSysUserAll - <== Total: 2
所以如果是以这种方式查询的话,数据一旦多了就会出现极大的性能问题
四、改进
<resultMap id="UserBaseResultMap2" type="com.layman.study.mybatis.pojo.SysUser">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
<result column="nick_name" property="nickName" jdbcType="VARCHAR"/>
<result column="salt" property="salt" jdbcType="VARCHAR"/>
<collection property="roleList" javaType="list" ofType="com.layman.study.mybatis.pojo.SysRole">
<id column="role_id" property="id"/>
<result column="role_name" property="roleName" jdbcType="VARCHAR"/>
<result column="role_code" property="roleCode" jdbcType="VARCHAR"/>
<result column="status" property="status" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</collection>
</resultMap> <select id="selectSysUserAll2" resultMap="UserBaseResultMap2">
select u.*,r.id role_id,r.role_name,r.role_code,r.status,r.create_time from
sys_user u join sys_user_role ur on u.id = ur.user_id join sys_role r on ur.role_id = r.id;
</select>
改进的方式为,直接使用一条语句直接关联查询出想要的信息:

只是在配置resultmap的时候稍有改变,但是查询的结果是一样的:
<resultMap id="UserBaseResultMap2" type="com.layman.study.mybatis.pojo.SysUser">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
<result column="nick_name" property="nickName" jdbcType="VARCHAR"/>
<result column="salt" property="salt" jdbcType="VARCHAR"/>
<collection property="roleList" javaType="list" ofType="com.layman.study.mybatis.pojo.SysRole">
<id column="role_id" property="id"/>
<result column="role_name" property="roleName" jdbcType="VARCHAR"/>
<result column="role_code" property="roleCode" jdbcType="VARCHAR"/>
<result column="status" property="status" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</collection>
</resultMap>
查询日志:
2017-02-16 17:28:21,370 [main] DEBUG transaction.SpringManagedTransaction - JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@3e74aff4] will not be managed by Spring
2017-02-16 17:28:21,381 [main] DEBUG SysUserDao.selectSysUserAll2 - ==> Preparing: select u.*,r.id role_id,r.role_name,r.role_code,r.status,r.create_time from sys_user u join sys_user_role ur on u.id = ur.user_id join sys_role r on ur.role_id = r.id;
2017-02-16 17:28:21,462 [main] DEBUG SysUserDao.selectSysUserAll2 - ==> Parameters:
2017-02-16 17:28:21,492 [main] DEBUG SysUserDao.selectSysUserAll2 - <== Total:
Mybatis关联查询<association> 和 <collection>的更多相关文章
- MyBatis关联查询 (association) 时遇到的某些问题/mybatis映射
先说下问题产生的背景: 最近在做一个用到MyBatis的项目,其中有个业务涉及到关联查询,我是将两个查询分开来写的,即嵌套查询,个人感觉这样更方便重用: 关联的查询使用到了动态sql,在执行查询时就出 ...
- mybatis 关联查询 association
<resultMap id="DutyPersonAndFileAndScoreMap" type="com.cares.asis.duty.entity.Duty ...
- Mybatis关联查询和数据库不一致问题分析与解决
Mybatis关联查询和数据库不一致问题分析与解决 本文的前提是,确定sql语句没有问题,确定在数据库中使用sql和项目中结果不一致. 在使用SpringMVC+Mybatis做多表关联时候,发现也不 ...
- MyBatis基础:MyBatis关联查询(4)
1. MyBatis关联查询简介 MyBatis中级联分为3中:association.collection及discriminator. ◊ association:一对一关联 ◊ collecti ...
- MyBatis关联查询,一对多关联查询
实体关系图,一个国家对应多个城市 一对多关联查询可用三种方式实现: 单步查询,利用collection标签为级联属性赋值: 分步查询: 利用association标签进行分步查询: 利用collect ...
- MyBatis关联查询、多条件查询
MyBatis关联查询.多条件查询 1.一对一查询 任务需求; 根据班级的信息查询出教师的相关信息 1.数据库表的设计 班级表: 教师表: 2.实体类的设计 班级表: public class Cla ...
- mybatis关联查询基础----高级映射
本文链接地址:mybatis关联查询基础----高级映射(一对一,一对多,多对多) 前言: 今日在工作中遇到了一个一对多分页查询的问题,主表一条记录对应关联表四条记录,关联分页查询后每页只显示三条记录 ...
- mybatis 关联查询实现一对多
场景:最近接到一个项目是查询管理人集合 同时每一个管理人还存在多个出资人 要查询一个管理人列表 每个管理人又包含了出资人列表 采用mybatis关联查询实现返回数据. 实现方式: 1 .在实体 ...
- Mybatis关联查询之二
Mybatis关联查询之多对多 多对多 一.entity实体类 public class Student { private Integer stuid; private String stuname ...
随机推荐
- 动态规划_Cow Bowling_POJ-3176
The cows don't use actual bowling balls when they go bowling. They each take a number (in the range ...
- Linux下安装配置Jmeter5.1,并执行jmx文件
Windows下的jmeter是GUI模式,可查看操作,但是GUI对性能的干扰比较大,所有一般压测会在Linux上运行. 下面是Linux下安装配置Jmeter5.1,并执行jmx文件的步骤, 一.安 ...
- 使用log4net记录ABP日志
demo地址:ABP.WindowsService 该文章是系列文章 基于.NetCore和ABP框架如何让Windows服务执行Quartz定时作业 的其中一篇. 参考:https://aspnet ...
- 在 alpine 中使用 NPOI
在 alpine 中使用 NPOI Intro 在 .net 中常使用 NPOI 来做 Excel 的导入导出,NPOI 从 2.4.0 版本开始支持 .netstandard2.0,对于.net c ...
- SQL和NoSQL的区别
一.概念 SQL (Structured Query Language) 数据库,指关系型数据库.主要代表:SQL Server,Oracle,MySQL(开源),PostgreSQL(开源). No ...
- fiddler设置断点
1.有两种方法设置断点 before response:也就是发送请求之后,但是Fiddler代理中转之前,这时可以修改请求的数据 after response:也就是服务器响应之后,但是在Fiddl ...
- java多线程基础(一)--sleep和wait的区别
sleep和wait的区别有: 1.这两个方法来自不同的类分别是Thread和Object: 2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得线程可以使用同步控制块或者方法: 3.w ...
- kafka消息的处理机制(五)
这一篇我们不在是探讨kafka的使用,前面几篇基本讲解了工作中的使用方式,基本api的使用还需要更深入的去钻研,多使用才会有提高.今天主要是探讨一下kafka的消息复制以及消息处理机制. 1. bro ...
- template.demo.js
<!DOCTYPE html><html><head> <title>index</title> <meta charset=&quo ...
- 《机器学习基石》---Linear Models for Classification
1 用回归来做分类 到目前为止,我们学习了线性分类,线性回归,逻辑回归这三种模型.以下是它们的pointwise损失函数对比(为了更容易对比,都把它们写作s和y的函数,s是wTx,表示线性打分的分数) ...