MyBatis series (twelve): use nested queries to achieve collection label

This blog mainly on the use of collection tags implement nested queries.

1. Demand Upgrade

In the blog post, we realized the demand: the user has acquired the role based user queries while the user id information.

Because the role can have multiple permissions, so this blog we upgrade requirements: obtaining permission roles include roles and owned by the user based on the user id to query the user information at the same time.

2. implementation

Because we need to use the mapping table permission, so we need to add the following mapping SysPrivilegeMapper.xml in:

<resultMap id="sysPrivilegeMap" type="com.zwwhnly.mybatisaction.model.SysPrivilege">
    <id property="id" column="id"/>
    <result property="privilegeName" column="privilege_name"/>
    <result property="privilegeUrl" column="privilege_url"/>
</resultMap>

Not propose to amend the database entity class corresponding to the table under normal circumstances, so here we create a new class SysRoleExtend, it inherited SysRole class, and add the following fields:

package com.zwwhnly.mybatisaction.model;

import java.util.List;

public class SysRoleExtend extends SysRole {
    /**
     * 角色包含的权限列表
     */
    private List<SysPrivilege> sysPrivilegeList;

    public List<SysPrivilege> getSysPrivilegeList() {
        return sysPrivilegeList;
    }

    public void setSysPrivilegeList(List<SysPrivilege> sysPrivilegeList) {
        this.sysPrivilegeList = sysPrivilegeList;
    }
}

Then the new mapping SysRoleMapper.xml the following:

<resultMap id="rolePrivilegeListMap" extends="roleMap"
           type="com.zwwhnly.mybatisaction.model.SysRoleExtend">
    <collection property="sysPrivilegeList" columnPrefix="privilege_"
                resultMap="com.zwwhnly.mybatisaction.mapper.SysPrivilegeMapper.sysPrivilegeMap"/>
</resultMap>

roleMap here in our previous blog has been defined, as follows:

<resultMap id="roleMap" type="com.zwwhnly.mybatisaction.model.SysRole">
    <id property="id" column="id"/>
    <result property="roleName" column="role_name"/>
    <result property="enabled" column="enabled"/>
    <result property="createBy" column="create_by"/>
    <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>

com.zwwhnly.mybatisaction.mapper.SysPrivilegeMapper.sysPrivilegeMapIs our newly erected in SysPrivilegeMapper.xml mapping sysPrivilegeMap.

Then, on the blog post in userRoleListMap you need to be amended as follows:

<resultMap id="userRoleListMap" type="com.zwwhnly.mybatisaction.model.SysUserExtend" extends="sysUserMap">
    <collection property="sysRoleList" columnPrefix="role_"
                resultMap="com.zwwhnly.mybatisaction.mapper.SysRoleMapper.rolePrivilegeListMap">
    </collection>
</resultMap>

And to amend Part blog, select the id tag codes selectAllUserAndRoles, because to be associated roles and permissions table permissions table:

<select id="selectAllUserAndRoles" resultMap="userRoleListMap">
    SELECT  u.id,
            u.user_name,
            u.user_password,
            u.user_email,
            u.create_time,
            r.id role_id,
            r.role_name role_role_name,
            r.enabled role_enabled,
            r.create_by role_create_by,
            r.create_time role_create_time,
            p.id role_privilege_id,
            p.privilege_name role_privilege_privilege_name,
            p.privilege_url role_privilege_privilege_url
    FROM sys_user u
    INNER JOIN sys_user_role ur ON u.id = ur.user_id
    INNER JOIN sys_role r ON ur.role_id = r.id
    INNER JOIN sys_role_privilege rp ON rp.role_id = r.id
    INNER JOIN sys_privilege p ON p.id = rp.privilege_id
</select>

Precautions:

Alias column name here sys_privilege table prefix role_privilege_because userRoleListMap in the collection of columnPrefix property role_, and specified com.zwwhnly.mybatisaction.mapper.SysRoleMapper.rolePrivilegeListMapin the collection of columnPrefix property privilege_, so here is a prefix required overlay, it becomes role_privilege_.

3. Unit Testing

Modify the test methods in Part blog built testSelectAllUserAndRoles () code:

@Test
public void testSelectAllUserAndRoles() {
    SqlSession sqlSession = getSqlSession();

    try {
        SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);

        List<SysUserExtend> sysUserList = sysUserMapper.selectAllUserAndRoles();
        System.out.println("用户数:" + sysUserList.size());
        for (SysUserExtend sysUser : sysUserList) {
            System.out.println("用户名:" + sysUser.getUserName());
            for (SysRoleExtend sysRoleExtend : sysUser.getSysRoleList()) {
                System.out.println("角色名:" + sysRoleExtend.getRoleName());
                for (SysPrivilege sysPrivilege : sysRoleExtend.getSysPrivilegeList()) {
                    System.out.println("权限名:" + sysPrivilege.getPrivilegeName());
                }
            }
        }
    } finally {
        sqlSession.close();
    }
}

Run the test code, the test passes, outputting the log follows:

DEBUG [main] - ==> Preparing: SELECT u.id, u.user_name, u.user_password, u.user_email, u.create_time, r.id role_id, r.role_name role_role_name, r.enabled role_enabled, r.create_by role_create_by, r.create_time role_create_time, p.id role_privilege_id, p.privilege_name role_privilege_privilege_name, p.privilege_url role_privilege_privilege_url FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id INNER JOIN sys_role_privilege rp ON rp.role_id = r.id INNER JOIN sys_privilege p ON p.id = rp.privilege_id

DEBUG [main] - ==> Parameters:

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time, role_id, role_role_name, role_enabled, role_create_by, role_create_time, role_privilege_id, role_privilege_privilege_name, role_privilege_privilege_url

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18: 21: 07.0, 1, administrators, 1, 1, 2019-06-27 18:21 : 12.0, 1, user management, / users

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18: 21: 07.0, 1, administrators, 1, 1, 2019-06-27 18:21 : 12.0, 2, role management, / roles

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18: 21: 07.0, 1, administrators, 1, 1, 2019-06-27 18:21 : 12.0, 3, system log, / logs

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18: 21: 07.0, 2, ordinary users, 1, 1, 2019-06-27 18:21 : 12.0, 4, maintenance personnel, / persons

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18: 21: 07.0, 2, ordinary users, 1, 1, 2019-06-27 18:21 : 12.0, 5, unit maintenance, / companies

TRACE [main] - <== Row: 1001, test, 123456, [email protected], 2019-06-27 18: 21: 07.0, 2, ordinary users, 1, 1, 2019-06-27 18:21 : 12.0, 4, maintenance personnel, / persons

TRACE [main] - <== Row: 1001, test, 123456, [email protected], 2019-06-27 18: 21: 07.0, 2, ordinary users, 1, 1, 2019-06-27 18:21 : 12.0, 5, unit maintenance, / companies

DEBUG [main] - <== Total: 7

Number of users: 2

Username: admin

Role name: Administrator

Permissions name: User Management

Permissions name: Role Management

Permissions Name: System Log

Role name: ordinary users

Permissions name: Maintenance personnel

Permissions name: Unit Maintenance

Username: test

Role name: ordinary users

Permissions name: Maintenance personnel

Permissions name: Unit Maintenance

As can be seen from the log, check out not only the role of information owned by the user, also check out the permission information contained in the role.

4. delay loading

Some students might say, the return of the role of information and permission information I do not necessarily use ah, each associated with so many queries a database table, good impact performance, ah, can not go when I use the role information that is acquired sysRoleList property database query it? The answer of course is energy, then how to achieve it?

Lazy loading required to achieve collection attribute tag fetchType, eager and lazy This property has two values, representing positive loading and delay loading.

Id because of the need to get all the right information corresponding to the role based on the role, so we must first define the following query in SysPrivilegeMapper.xml in:

<select id="selectPrivilegeByRoleId" resultMap="sysPrivilegeMap">
    SELECT p.*
    FROM sys_privilege p
    INNER JOIN sys_role_privilege rp ON rp.privilege_id = p.id
    WHERE rp.role_id = #{roleId}
</select>

Then add the following query in SysRoleMapper.xml in:

<resultMap id="rolePrivilegeListMapSelect" extends="roleMap"
           type="com.zwwhnly.mybatisaction.model.SysRoleExtend">
    <collection property="sysPrivilegeList" fetchType="lazy"
                column="{roleId=id}"
                select="com.zwwhnly.mybatisaction.mapper.SysPrivilegeMapper.selectPrivilegeByRoleId"/>
</resultMap>
<select id="selectRoleByUserId" resultMap="rolePrivilegeListMapSelect">
    SELECT
          r.id,
          r.role_name,
          r.enabled,
          r.create_by,
          r.create_time
    FROM sys_role r
    INNER JOIN sys_user_role ur ON ur.role_id = r.id
    WHERE ur.user_id = #{userId}
</select>

Above column="{roleId=id}"in, roleId refers to the method specified selectPrivilegeByRoleId select the parameters, id refers to the query selectRoleByUserId query the role id.

Then add the following query in SysUserMapper.xml in:

<resultMap id="userRoleListMapSelect" extends="sysUserMap"
           type="com.zwwhnly.mybatisaction.model.SysUserExtend">
    <collection property="sysRoleList" fetchType="lazy"
                select="com.zwwhnly.mybatisaction.mapper.SysRoleMapper.selectRoleByUserId"
                column="{userId=id}"/>
</resultMap>
<select id="selectAllUserAndRolesSelect" resultMap="userRoleListMapSelect">
    SELECT
          u.id,
          u.user_name,
          u.user_password,
          u.user_email,
          u.create_time
    FROM sys_user u
    WHERE u.id = #{id}
</select>

Above column="{userId=id}"the, userId refers to a method specified selectRoleByUserId select parameters, id refers query query selectAllUserAndRolesSelect out user id.

Then, in SysUserMapper interface, add the following method:

/**
 * 通过嵌套查询获取指定用户的信息以及用户的角色和权限信息
 *
 * @param id
 * @return
 */
SysUserExtend selectAllUserAndRolesSelect(Long id);

Finally, add the following test method SysUserMapperTest class:

@Test
public void testSelectAllUserAndRolesSelect() {
    SqlSession sqlSession = getSqlSession();

    try {
        SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);

        SysUserExtend sysUserExtend = sysUserMapper.selectAllUserAndRolesSelect(1L);
        System.out.println("用户名:" + sysUserExtend.getUserName());
        for (SysRoleExtend sysRoleExtend : sysUserExtend.getSysRoleList()) {
            System.out.println("角色名:" + sysRoleExtend.getRoleName());
            for (SysPrivilege sysPrivilege : sysRoleExtend.getSysPrivilegeList()) {
                System.out.println("权限名:" + sysPrivilege.getPrivilegeName());
            }
        }
    } finally {
        sqlSession.close();
    }
}

Running the test method, the log output as follows:

DEBUG [main] - ==> Preparing: SELECT u.id, u.user_name, u.user_password, u.user_email, u.create_time FROM sys_user u WHERE u.id = ?

DEBUG [main] - ==> Parameters: 1(Long)

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

Username: admin

DEBUG [main] - ==> Preparing: SELECT r.id, r.role_name, r.enabled, r.create_by, r.create_time FROM sys_role r INNER JOIN sys_user_role ur ON ur.role_id = r.id WHERE ur.user_id = ?

DEBUG [main] - ==> Parameters: 1(Long)

TRACE [main] - <== Columns: id, role_name, enabled, create_by, create_time

TRACE [main] - <== Row: 1, the administrator, 1, 1, 2019-06-2718: 21: 12.0

TRACE [main] - <== Row: 2, ordinary users, 1, 1, 2019-06-2718: 21: 12.0

DEBUG [main] - <== Total: 2

Role name: Administrator

DEBUG [main] - ==> Preparing: SELECT p.* FROM sys_privilege p INNER JOIN sys_role_privilege rp ON rp.privilege_id = p.id WHERE rp.role_id = ?

DEBUG [main] - ==> Parameters: 1(Long)

TRACE [main] - <== Columns: id, privilege_name, privilege_url

TRACE [main] - <== Row: 1, user management, / users

TRACE [main] - <== Row: 2, role management, / roles

TRACE [main] - <== Row: 3, system log, / logs

DEBUG [main] - <== Total: 3

Permissions name: User Management

Permissions name: Role Management

Permissions Name: System Log

Role name: ordinary users

DEBUG [main] - ==> Preparing: SELECT p.* FROM sys_privilege p INNER JOIN sys_role_privilege rp ON rp.privilege_id = p.id WHERE rp.role_id = ?

DEBUG [main] - ==> Parameters: 2(Long)

TRACE [main] - <== Columns: id, privilege_name, privilege_url

TRACE [main] - <== Row: 4, maintenance personnel, / persons

TRACE [main] - <== Row: 5, maintenance units, / companies

DEBUG [main] - <== Total: 2

Permissions name: Maintenance personnel

Permissions name: Unit Maintenance

When the log careful analysis of the above, you will find only in the use of information and authority to the role of information, before the implementation of the corresponding database queries.

It should be noted that the delay in loading depends on MyBatis global configuration aggressiveLazyLoading, while in the previous blog to explain the association label, we have to configure it to false, so the results here is in line with our expectations:

<settings>
    <!--其他配置-->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

Explain in detail about the parameters, see the MyBatis from entry to the master (X): Use the association to achieve tags nested queries .

5. Summary

Use label collection implement nested query, use the properties are summarized as follows:

1) select: id, MyBatis extra another mapping query execution results of this query to get nested objects.

2) column: main column query results as a parameter nested queries, configuration such as column = "{prop1 = col1, prop2 = col2}", prop1 prop2 as a parameter, and a nested query.

3) fetchType: data loading, eager and lazy optional values, respectively, loading and delay loading active.

4) To use lazy loading, except that the lazy fetchType set, is also noted that the global configuration values ​​aggressiveLazyLoading be false. This parameter defaults ture prior to version 3.4.5, version 3.4.5 from the beginning of the default value was changed to false.

5) lazyLoadTriggerMethods parameters MyBatis provided support queries directly trigger lazy loading property when triggered some methods, such as equals () method.

6. Source and reference

Source Address: https://github.com/zwwhnly/mybatis-action.git , welcome to download.

Liuzeng Hui "MyBatis from entry to the master."

The original is not easy, if that article can learn something, like a welcome point, a commentary on, off a note, this is my greatest motivation insist on writing.

If you are interested, please add my micro letter: zwwhnly , waiting for you to talk technology, workplace, work and other topics (PS: I am a programmer struggle in Shanghai).

Published 34 original articles · won praise 107 · views 20000 +

Guess you like

Origin blog.csdn.net/zwwhnly/article/details/103799237