Серия MyBatis (двенадцать): используйте тег collection для реализации вложенных запросов.

MyBatis

В этом блоге в основном объясняется, как использовать тег коллекции для реализации вложенных запросов.

1. Требуйте обновления

В последнем блоге мы реализовали требование: запрашивать информацию о пользователе на основе идентификатора пользователя и получать роли, принадлежащие пользователю.

Поскольку у ролей может быть несколько разрешений, наши требования к обновлению в этом блоге таковы: запрашивать информацию о пользователе на основе идентификатора пользователя и получать роли, принадлежащие пользователю, и разрешения, содержащиеся в роли.

2. Реализация

Поскольку нам нужно использовать сопоставление с таблицей привилегий, нам нужно сначала добавить следующее сопоставление в SysPrivilegeMapper.xml:

<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>

В обычных условиях не рекомендуется модифицировать класс сущности, соответствующий таблице базы данных, поэтому здесь мы создаем новый класс SysRoleExtend, позволяем ему наследовать класс SysRole и добавляем следующие поля:

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;
    }
}

Затем создайте следующее сопоставление в SysRoleMapper.xml:

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

Ролевую карту здесь мы определили в предыдущем блоге, код выглядит следующим образом:

<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.sysPrivilegeMapЭто новое сопоставление sysPrivilegeMap, которое мы только что создали в SysPrivilegeMapper.xml.

Затем вам нужно изменить userRoleListMap в предыдущем блоге на:

<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>

И вам нужно изменить код тега select с идентификатором selectAllUserAndRoles в предыдущем блоге, потому что вы хотите связать таблицу отношений разрешений роли с таблицей разрешений:

<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>

Меры предосторожности:

Здесь префикс псевдонимов имен столбцов таблицы sys_privacy равенrole_privilege_, это связано с тем, что свойство columnPrefix коллекции в userRoleListMap равноrole_, и указанныйcom.zwwhnly.mybatisaction.mapper.SysRoleMapper.rolePrivilegeListMapСвойство columnPrefix коллекцииprivilege_, поэтому префиксы здесь нужно накладывать друг на друга, и получаетсяrole_privilege_.

3. Модульное тестирование

Измените код тестового метода testSelectAllUserAndRoles(), созданный в предыдущем блоге, следующим образом:

@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();
    }
}

Запустите тестовый код, тест пройден, и выходной журнал выглядит следующим образом:

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] -

TRACE [main] -

TRACE [main] -

TRACE [main] -

TRACE [main] -

TRACE [main] -

TRACE [main] -

DEBUG [main] - <== Total: 7

Количество пользователей: 2

Имя пользователя: админ

имя роли: администратор

Имя разрешения: управление пользователями

Имя разрешения: управление ролями

Имя разрешения: системный журнал

Имя роли: обычный пользователь

Имя разрешения: Обслуживание персонала

Имя разрешения: техническое обслуживание объекта

Имя пользователя: тест

Имя роли: обычный пользователь

Имя разрешения: Обслуживание персонала

Имя разрешения: техническое обслуживание объекта

Из журнала видно, что запрашивается не только информация о роли, принадлежащая пользователю, но и информация о разрешениях, содержащаяся в роли.

4. Ленивая загрузка

Некоторые учащиеся могут сказать, что я не обязательно использую возвращаемую информацию о роли и информацию о разрешениях. Каждый раз, когда я связываю так много таблиц и один раз запрашиваю базу данных, это влияет на производительность. Могу ли я перейти к атрибуту sysRoleList при использовании роли информация? А как насчет запросов к базе данных? Конечно, да, но как?

Чтобы реализовать отложенную загрузку, вам нужно использовать атрибут fetchType тега collection, который имеет два значения, отложенное и нетерпеливое, представляющие соответственно отложенную загрузку и активную загрузку.

Поскольку вся информация о разрешениях, соответствующая роли, должна быть получена в соответствии с идентификатором роли, мы должны сначала определить следующий запрос в SysPrivilegeMapper.xml:

<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>

Затем добавьте следующий запрос в SysRoleMapper.xml:

<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>

вышеcolumn="{roleId=id}", roleId относится к параметру метода selectPrivilegeByRoleId, указанному в select, а id относится к идентификатору роли, запрошенному в запросе selectRoleByUserId.

Затем добавьте следующий запрос в SysUserMapper.xml:

<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>

вышеcolumn="{userId=id}", userId относится к параметру метода selectRoleByUserId, указанному в select, а id относится к идентификатору пользователя, запрашиваемому в запросе selectAllUserAndRolesSelect.

Затем в интерфейсе SysUserMapper добавьте следующий метод:

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

Наконец, добавьте следующий тестовый метод в класс SysUserMapperTest:

@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();
    }
}

Запустите тестовый метод, и выходной журнал будет выглядеть следующим образом:

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, admin@mybatis.tk, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

Имя пользователя: админ

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] -

TRACE [main] -

DEBUG [main] - <== Total: 2

имя роли: администратор

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] -

TRACE [main] -

TRACE [main] -

DEBUG [main] - <== Total: 3

Имя разрешения: управление пользователями

Имя разрешения: управление ролями

Имя разрешения: системный журнал

Имя роли: обычный пользователь

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 [основная] -

TRACE [основная] -

DEBUG [main] - <== Total: 2

Имя разрешения: Обслуживание персонала

Имя разрешения: техническое обслуживание объекта

Внимательно проанализировав приведенный выше журнал, вы обнаружите, что соответствующий запрос к базе данных выполняется только тогда, когда используется информация о роли и информация о разрешениях.

Следует отметить, что отложенная загрузка зависит от AgressLazyLoading в глобальной конфигурации MyBatis, При объяснении тега ассоциации в предыдущем блоге мы настроили его на false, поэтому результат выполнения здесь соответствует нашим ожиданиям:

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

Подробное объяснение этого параметра см.MyBatis от входа до мастерства (десять): используйте теги ассоциации для реализации вложенных запросов.

5. Резюме

Используйте тег collection для реализации вложенных запросов.Используемые атрибуты резюмируются следующим образом:

1) select: идентификатор другого запроса отображения, MyBatis дополнительно выполнит этот запрос, чтобы получить результаты вложенных объектов.

2) столбец: результат столбца в основном запросе используется в качестве параметра вложенного запроса.Метод конфигурации: column="{prop1=col1,prop2=col2}", а prop1 и prop2 будут использоваться в качестве параметра вложенного запроса. параметры вложенного запроса.

3) fetchType: метод загрузки данных, необязательные значения — ленивая и активная загрузка соответственно.

4) Если вы хотите использовать ленивую загрузку, помимо установки fetchType в lazy, вам также необходимо отметить, что значение глобальной конфигурации AgressLazyLoading должно быть ложным. Значение по умолчанию для этого параметра было true до версии 3.4.5, а начиная с версии 3.4.5 значение по умолчанию было изменено на false.

5) Параметр lazyLoadTriggerMethods, предоставляемый MyBatis, поддерживает прямой запуск запроса свойств отложенной загрузки при запуске метода, например, метода equals().

6. Исходный код и ссылка

Адрес источника:GitHub.com/Как Ухань, где/каждый шаг…, добро пожаловать на скачивание.

Лю Цзэнхуэй "MyBatis от входа до мастерства"