• 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: 3 
  • 相关阅读:
    (C/C++学习笔记) 十四. 动态分配
    (C/C++学习笔记) 十三. 引用
    (C/C++学习笔记) 十二. 指针
    (C/C++学习笔记) 十一. 数组
    (C/C++学习笔记) 十. 函数
    (C/C++学习笔记) 九. 变量的存储类型
    (C/C++学习笔记) 八. 程序控制语句
    并发编程之多进程
    网络编程之Socket
    异常处理
  • 原文地址:https://www.cnblogs.com/Laymen/p/6406793.html
Copyright © 2020-2023  润新知