В этом блоге в основном объясняется, как использовать тег коллекции для реализации вложенных запросов.
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 от входа до мастерства"