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 ...
随机推荐
- 初探java流操作
在处理集合时,我们通常会迭代遍历它的元素,并从每个元素上执行某项操作.例如,假设我们想要对某本书中的所有长单词进行计数.首先我们要将所有单词放入一个列表中: String contents = new ...
- python3 导入包总提示no moudle named xxx
一.python中的包有三种 1.python自带的包,如sys, os 2.python的第三方库,如 requests, selenium 3.自己写的.py文件 二.今天主要说下导入自己写的包 ...
- T-SQL 镜像测试
--====================================================== ----镜像计划建立 2016-05-10 17:05:16.463 hubiyun ...
- 极简代码神器:Lombok使用教程
Lombok 是一个非常神奇的 java 类库,会利用注解自动生成 java Bean 中烦人的 Getter.Setter,还能自动生成 logger.ToString.HashCode.Build ...
- Charles PC端和手机端抓取HTTP和HTTPS协议请求、HTTPS通用抓包规则
一:HTTP和HTTPS的区别 HTTP是超文本传输协议,被用在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,因此HTTP协议不适合传输一些敏感信息, ...
- Spring JdbcTemplate之使用详解
最近在项目中使用到了 Spring 的 JdbcTemplate, 中间遇到了好多坑, 所以花一些时间对 JdbcTemplate 的使用做了一个总结, 方便以后自己的查看.文章中贴出来的API都是经 ...
- JAVA并发之阻塞队列浅析
背景 因为在工作中经常会用到阻塞队列,有的时候还要根据业务场景获取重写阻塞队列中的方法,所以学习一下阻塞队列的实现原理还是很有必要的.(PS:不深入了解的话,很容易使用出错,造成没有技术深度的样子) ...
- 使用 Docker 生成 Let’s Encrypt 证书
概念 什么是 Container ? https://www.docker.com/resources/what-container https://www.docker.com/why-docker ...
- 《HTTP权威指南》--阅读笔记(一)
HTTP: HyperText Transfer Protocol 测试站点:http://www.joes-hardware.com URI包括URL和URN URI: Uniform Resour ...
- zookeeper基本知识入门(一)
之前我们在搭建hadoop分布式环境的时候用到过Zookeeper注册hadoop服务.那么到底Zookeeper在分布式环境中发挥了什么作用呢,这次我们就来讨论这个问题. 在分布式系统中通常都会有多 ...