一、背景

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>的更多相关文章

  1. MyBatis关联查询 (association) 时遇到的某些问题/mybatis映射

    先说下问题产生的背景: 最近在做一个用到MyBatis的项目,其中有个业务涉及到关联查询,我是将两个查询分开来写的,即嵌套查询,个人感觉这样更方便重用: 关联的查询使用到了动态sql,在执行查询时就出 ...

  2. mybatis 关联查询 association

    <resultMap id="DutyPersonAndFileAndScoreMap" type="com.cares.asis.duty.entity.Duty ...

  3. Mybatis关联查询和数据库不一致问题分析与解决

    Mybatis关联查询和数据库不一致问题分析与解决 本文的前提是,确定sql语句没有问题,确定在数据库中使用sql和项目中结果不一致. 在使用SpringMVC+Mybatis做多表关联时候,发现也不 ...

  4. MyBatis基础:MyBatis关联查询(4)

    1. MyBatis关联查询简介 MyBatis中级联分为3中:association.collection及discriminator. ◊ association:一对一关联 ◊ collecti ...

  5. MyBatis关联查询,一对多关联查询

    实体关系图,一个国家对应多个城市 一对多关联查询可用三种方式实现: 单步查询,利用collection标签为级联属性赋值: 分步查询: 利用association标签进行分步查询: 利用collect ...

  6. MyBatis关联查询、多条件查询

    MyBatis关联查询.多条件查询 1.一对一查询 任务需求; 根据班级的信息查询出教师的相关信息 1.数据库表的设计 班级表: 教师表: 2.实体类的设计 班级表: public class Cla ...

  7. mybatis关联查询基础----高级映射

    本文链接地址:mybatis关联查询基础----高级映射(一对一,一对多,多对多) 前言: 今日在工作中遇到了一个一对多分页查询的问题,主表一条记录对应关联表四条记录,关联分页查询后每页只显示三条记录 ...

  8. mybatis 关联查询实现一对多

    场景:最近接到一个项目是查询管理人集合  同时每一个管理人还存在多个出资人   要查询一个管理人列表  每个管理人又包含了出资人列表 采用mybatis关联查询实现返回数据. 实现方式: 1 .在实体 ...

  9. Mybatis关联查询之二

    Mybatis关联查询之多对多 多对多 一.entity实体类 public class Student { private Integer stuid; private String stuname ...

随机推荐

  1. 初探java流操作

    在处理集合时,我们通常会迭代遍历它的元素,并从每个元素上执行某项操作.例如,假设我们想要对某本书中的所有长单词进行计数.首先我们要将所有单词放入一个列表中: String contents = new ...

  2. python3 导入包总提示no moudle named xxx

    一.python中的包有三种 1.python自带的包,如sys, os 2.python的第三方库,如 requests, selenium 3.自己写的.py文件 二.今天主要说下导入自己写的包 ...

  3. T-SQL 镜像测试

    --====================================================== ----镜像计划建立 2016-05-10 17:05:16.463 hubiyun ...

  4. 极简代码神器:Lombok使用教程

    Lombok 是一个非常神奇的 java 类库,会利用注解自动生成 java Bean 中烦人的 Getter.Setter,还能自动生成 logger.ToString.HashCode.Build ...

  5. Charles PC端和手机端抓取HTTP和HTTPS协议请求、HTTPS通用抓包规则

    一:HTTP和HTTPS的区别 HTTP是超文本传输协议,被用在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,因此HTTP协议不适合传输一些敏感信息, ...

  6. Spring JdbcTemplate之使用详解

    最近在项目中使用到了 Spring 的 JdbcTemplate, 中间遇到了好多坑, 所以花一些时间对 JdbcTemplate 的使用做了一个总结, 方便以后自己的查看.文章中贴出来的API都是经 ...

  7. JAVA并发之阻塞队列浅析

    背景 因为在工作中经常会用到阻塞队列,有的时候还要根据业务场景获取重写阻塞队列中的方法,所以学习一下阻塞队列的实现原理还是很有必要的.(PS:不深入了解的话,很容易使用出错,造成没有技术深度的样子) ...

  8. 使用 Docker 生成 Let’s Encrypt 证书

    概念 什么是 Container ? https://www.docker.com/resources/what-container https://www.docker.com/why-docker ...

  9. 《HTTP权威指南》--阅读笔记(一)

    HTTP: HyperText Transfer Protocol 测试站点:http://www.joes-hardware.com URI包括URL和URN URI: Uniform Resour ...

  10. zookeeper基本知识入门(一)

    之前我们在搭建hadoop分布式环境的时候用到过Zookeeper注册hadoop服务.那么到底Zookeeper在分布式环境中发挥了什么作用呢,这次我们就来讨论这个问题. 在分布式系统中通常都会有多 ...