一、背景

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. 确保Web安全的HTTPS

    HTTP在安全方面主要有以下不足: 1. 通信使用明文不加密,内容可能会被窃听:(TCP/IP就是可能被窃听的网络) 2. 不验证通信方的身份,因此有可能遭遇伪装: (无法判断请求或响应是否正确,是否 ...

  2. activeMQ_helloworld(一)

    一.activeMQ下载,直接在Linux上wget http://mirror.bit.edu.cn/apache//activemq/5.14.5/apache-activemq-5.14.5-b ...

  3. 【iOS】判断苹果的设备是哪种

    有时候需要判断苹果的设备是 iPhone 还是 iPad 等其他设备,示例代码如下: if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUs ...

  4. js页面3秒自动跳转

    如何让当前页面3秒以后自动跳转到其他页面?JS页面自动跳转 想实现登陆后3秒自动跳转到某页的功能,在网上搜了一下,供以后使用 1.<script   language= "javasc ...

  5. Java匹马行天下之J2EE框架开发——Spring—>用IDEA开发Spring程序(01)

    一.心动不如行动 一.创建项目 *注:在IDEA中我创建的Maven项目,不了解Maven的朋友可以看我之前的博客“我们一起走进Maven——知己知彼”,了解Maven后可以看我之前的博客“Maven ...

  6. HackBar收费版绕过

    一段时间没用HackBar,近期做渗透,打开火狐浏览器,按F12键调出HackBar,发现居然需要收费买license才能使用. 经过研究,整理了以下两个绕过HackBar收费版的方法. 第一种:用其 ...

  7. 前端笔记之微信小程序(四)WebSocket&Socket.io&摇一摇案例&地图|地理位置

    一.WebSocket概述 http://www.ruanyifeng.com/blog/2017/05/websocket.html Workerman一款开源高性能异步PHP socket即时通讯 ...

  8. Spark 系列(三)—— 弹性式数据集RDDs

    一.RDD简介 RDD 全称为 Resilient Distributed Datasets,是 Spark 最基本的数据抽象,它是只读的.分区记录的集合,支持并行操作,可以由外部数据集或其他 RDD ...

  9. 基于Starling的mask实现

    作为一个从c++转过来的程序员,flash原生的自定义mask实在是太好用,能方便实现各种效果,比如新手引导的高亮.viewport效果等.可惜starling的显示对象并不支持mask特性,查阅go ...

  10. Amazon S3

    Amazon S3 是什么? Amazon S3 是亚马逊推出的一款存储服务,名为 Amazon Simple Storage Service,即亚马逊简单存储服务. 有些 S3 的概念需要了解一下: ...