MyBatis-21MyBatis高级结果映射【一对多映射(2种方式)】

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: MyBatis-21MyBatis高级结果映射【一对多映射(2种方式)】

概述

MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】中我们介绍了4种方式实现一对一映射,本篇博文,一对多映射只有两种配置方式,都是使用collection标签进行的。


collection集合的嵌套结果映射


和association类似,集合的嵌套结果映射就是通过一次SQL查询将所有的结果查询出来,然后通过配置的结果映射,将数据映射到不同的对象中取。 在一对多的关系中,主表的一条数据会对应关联表中的多条数据,因此一般查询时会查询出多个结果,按照一对多的数据结果存储数据的时候,最终的结果会小于等于查询的总记录数。


在RBAC权限系统中,一个用户用于多个角色(在使用association是设定的特例,现在一个用户只能有一个角色),每个角色又是多个权限的集合,所以要渐进式的去实现一个SQL,查询出所有用户和用户拥有的角色,以及角色所包含的所有权限信息的两层嵌套结果。


SysUse实体类改造

为了能够存储一对多的数据,先对SysUser类进行修改

增加

public class SysUser{
  // 原有属性, setter getter保持不变 
  /**
   * 用户角色: 一个用户拥有多个角色 , 一对多
   */
  private List<SysRole>  roleList;
  public List<SysRole> getRoleList() {
    return roleList;
  }
  public void setRoleList(List<SysRole> roleList) {
    this.roleList = roleList;
  }
}


UserMapper接口增加接口方法

/**
   * 
   * 
   * @Title: selectAllUserAndRoles
   * 
   * @Description:获取所有用户及对应的角色
   * 
   * @return
   * 
   * @return: List<SysUser>
   */
  List<SysUser> selectAllUserAndRoles()


UserMapper.xml

<!-- 简化的配置 -->
  <resultMap id="userRoleListMap" extends="userMap"
         type="com.artisan.mybatis.xml.domain.SysUser" >
    <!-- sysRole相关的属性   property 对应实体类List<SysRole>属性名-->
    <collection property="roleList" columnPrefix="sysRole_"
      resultMap="roleMap">
    </collection>
  </resultMap>
<select id="selectAllUserAndRoles" resultMap="userRoleListMap">
    SELECT
      u.id,
      u.user_name ,
      u.user_password ,
      u.user_email ,
      u.user_info ,
      u.create_time ,
      u.head_img ,
      r.id sysRole_id,
      r.role_name sysRole_role_name,
      r.enabled sysRole_enabled,
      r.create_by sysRole_create_by,
      r.create_time sysRole_create_time
    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
  </select>


和一对一映射相比,一对多的userRoleListMap,就是把association改成collection, 然后将property设置为roleList,其他的属性保持不变。


collection用于配置一对多的关系,对应的属性必须是对象中的集合类型,因此这里是roleList。 另外resultMap只是为了配置数据库字段和实体属性的映射关系,因此其他都一样。 同时能存储一对多的数据结构肯定也能存储一对一的关系,所以一对一是一对多的一种特例。 collection支持的属性以及属性的作用和association完全相同。


为了简化配置,我们通过继承userMap来使用sys_user的映射关系,同时我们在UserMapper.xml中配置了roleMap的映射关系(更加合适的问题应该在RoleMapper.xml中,如果在RoleMapper.xml中,引用的时候一定要加上命名空间),因此直接饮用roleMap ,经过这两个方式的简化,最终的userRoleListMap如上


总结下:一对多配置变化的地方是 association变为collection, property由role变为了roleList


单元测试

@Test
  public void selectAllUserAndRolesTest() {
    logger.info("selectAllUserAndRolesTest");
    // 获取SqlSession
    SqlSession sqlSession = getSqlSession();
    try {
      // 获取UserMapper接口
      UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
      // 调用selectAll,查询全部用户
      List<SysUser> userList = userMapper.selectAllUserAndRoles();
      // 结果不为空
      Assert.assertNotNull(userList);
      // 结果大于0
      Assert.assertTrue(userList.size() > 0);
      logger.info("userList总数为:" + userList.size());
      for (SysUser sysUser : userList) {
        logger.info("用户名:" + sysUser.getUserName());
        for (SysRole sysRole : sysUser.getRoleList()) {
          logger.info("\t角色名:" + sysRole.getRoleName());
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      sqlSession.close();
      logger.info("sqlSession close successfully ");
    }
  }


我们在 Assert.assertNotNull(userList); 加上个断点,debug看下数据


20180502235343413.png


点进去一个看下


20180502235545936.png


从上图可以看到一个用于已经拥有两个角色,实现了一对多的查询。

接下来看下日志

2018-05-02 02:02:26,338  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-05-02 02:02:26,343  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-05-02 02:02:26,346  INFO [main] (UserMapperTest.java:1133) - selectAllUserAndRolesTest
2018-05-02 02:02:26,415 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time 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 
2018-05-02 02:02:26,538 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 
2018-05-02 02:02:26,586 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time
2018-05-02 02:02:26,587 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 02:02:26,598 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 02:02:26,600 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 02:02:26,602 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 3
2018-05-02 02:02:26,604  INFO [main] (UserMapperTest.java:1146) - userList总数为:2
2018-05-02 02:02:26,604  INFO [main] (UserMapperTest.java:1148) - 用户名:admin
2018-05-02 02:02:26,604  INFO [main] (UserMapperTest.java:1150) -   角色名:管理员
2018-05-02 02:02:26,605  INFO [main] (UserMapperTest.java:1150) -   角色名:普通用户
2018-05-02 02:02:26,605  INFO [main] (UserMapperTest.java:1148) - 用户名:artisan
2018-05-02 02:02:26,605  INFO [main] (UserMapperTest.java:1150) -   角色名:普通用户
2018-05-02 02:02:26,608  INFO [main] (UserMapperTest.java:1157) - sqlSession close successfully 


MyBatis的处理规则


通过日志可以清楚地看到,SQL执行的结果数有3条,用户输出的数量确实2条,也就是说本来查询出的3条结果经过MyBatis对collection数据的处理后,变成了2条。


从日志中,我们知道第一个用户拥有两个角色,所以转换为一对多的数据结构后就变成了两套结果,那么 MyBatis又是怎么知道要处理成这样的结果呢?


先来看MyBatis是如何要知道合并admin的两条数据的,为什么不把test这条数据也合并进去呢?


MyBatis在处理结果的时候,会判断结果是否相同,如果是相同的结果,则只会保留第一个结果。 所以这个问题的关键点就是MyBatis是如何判断结果是否相同。 最简单的情况就是在映射配置中至少有一个id标签

<id property="id" column="id"  />


我们对id的理解一般是,它配置的字段为表的主键(联合主键时可以配置多个id标签),因为MyBatis的resultMap只用于配置结果如何映射,并不知道这个表具体如何。 id的唯一作用就是在嵌套的映射配置中判断数据是否相同。 .当配置id标签时,MyBatis只需要逐条比较所有数据中id标签的字段值是否相同即可。 在配置嵌套结果查询时,配置id标签提高处理效率。


这样一来,上面的查询就不难理解了,因为前两套数据的userMap部分的id相同,所以他们属于同一个用户,因子这条数据会合并到同一个用户中。


为了更加清楚的理解id的作用,我们队userMap的映射进行如下修改。

<resultMap id="userMap" 
         type="com.artisan.mybatis.xml.domain.SysUser">
    <id property="userPassword" column="userPassword"  />
    <result property="userName" column="user_name" />
    <result property="userPassword" column="user_password" />
    <result property="userEmail" column="user_email" />
    <result property="userInfo" column="user_info" />
    <result property="headImg" column="head_img" jdbcType="BLOB" />
    <result property="createTime" column="create_time" jdbcType="TIMESTAMP" />
  </resultMap>


在测试数据中,用户的密码均为 123456


20180503002255876.png


如果把密码最为id,按照上面的逻辑,3条数据就会合并为1条数据,修改后,再次执行单元测试。

2018-05-02 12:24:27,161  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-05-02 12:24:27,161  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-05-02 12:24:27,173  INFO [main] (UserMapperTest.java:1133) - selectAllUserAndRolesTest
2018-05-02 12:24:27,253 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time 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 
2018-05-02 12:24:27,383 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 
2018-05-02 12:24:27,433 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time
2018-05-02 12:24:27,433 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 12:24:27,443 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 12:24:27,443 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-05-02 12:24:27,443 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 3
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1146) - userList总数为:1
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1148) - 用户名:admin
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1150) -   角色名:管理员
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1150) -   角色名:普通用户
2018-05-02 12:24:27,443  INFO [main] (UserMapperTest.java:1157) - sqlSession close successfully 
 userList总数为:1
 用户名:admin
  角色名:管理员
  角色名:普通用户


用户信心保留的是第一条数据的信心,因此用户名是admin . 角色为什么不是3个呢? 因为“普通用户”这个角色重复了,所以也只保留第一个出现的“普通用户”。 因为MyBatis会对嵌套查询的每一级对象都进行属性比较。 MyBatis会首先比较顶层的对象,如果SysUser相同,就继续比较SysRole部分,如果SysRole不同,就会增加一个sysRole,两个SysROle相同就保留前一个。 假设SysRole还有下一级,仍然按照该规则去比较。


通过上述这个例子应该明白了id的作用了,需要注意的是,很肯能出现一种没有配置id的情况。 当没有配置id的时候,MyBatis就会把resultMap中配置的说哟字段进行比较,如果所有字段的值都相同就合并,只要有一个字段值不同,就不合并。


在嵌套结果配置id属性时,如果查询中没有查询id属性配置的列,就会导致id对应的值为null.这种情况下,所有的id都相同,因此会使嵌套的集合中只有一条数据。 所以在配置id列时,查询语句中必须包含该列。


可以对userMap再次改造,将id标签改为result标签,执行结果是一样的,由于MyBatis要对所有字段字段进行比较,因此当字段数为M时,如果查询结果有N条,就需要进行M*N,相比配置id时的N次比较,效率差很多。 所以尽量配置id标签.

<result property="id" column="id"/>

两层嵌套


在RBAC权限系统中,除了一个用户对应多个角色外,每个角色还会对应多个权限,在上个例子的基础上我们增加一级,获取角色对应的所有权限。


PrivilegeMap.xml增加映射


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
          "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!-- 当Mapper接口和XML文件关联的时候, namespace的值就需要配置成接口的全限定名称 -->
<mapper namespace="com.artisan.mybatis.xml.mapper.PrivilegeMapper">
  <resultMap id="privilegeMap" type="com.artisan.mybatis.xml.domain.SysPrivilege">
    <id property="id" column="id" />
    <result property="privilegeName" column="privilege_name" />
    <result property="privilegeUrl" column="privilege_url" />
  </resultMap>
</mapper>             

SysRole实体类改造

增加

  /**
   * 一对多,权限集合
   */
  List<SysPrivilege> privilegeList;
  public List<SysPrivilege> getPrivilegeList() {
    return privilegeList;
  }
  public void setPrivilegeList(List<SysPrivilege> privilegeList) {
    this.privilegeList = privilegeList;
  }


RoleMapper.xml文件中增加如下resultMap

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
          "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!-- 当Mapper接口和XML文件关联的时候, namespace的值就需要配置成接口的全限定名称 -->
<mapper namespace="com.artisan.mybatis.xml.mapper.RoleMapper">
  <resultMap id="rolePrivilegeListMap" 
    type="com.artisan.mybatis.xml.domain.SysRole"
    extends="com.artisan.mybatis.xml.mapper.UserMapper.roleMap">
    <collection property="privilegeList" columnPrefix="privilege_"
      resultMap="com.artisan.mybatis.xml.mapper.PrivilegeMapper.privilegeMap" />
  </resultMap>
</mapper> 


我们创建了角色权限映射,继承了roleMap,嵌套了privilegeList属性,直接使用PrivilegeMapper.xml中的privilegeMap。


UserMapper.xml改造

<resultMap id="userRoleAndPrivilegeListMap" extends="userMap"
         type="com.artisan.mybatis.xml.domain.SysUser" >
    <collection property="roleList" columnPrefix="sysRole_"
      resultMap="com.artisan.mybatis.xml.mapper.RoleMapper.rolePrivilegeListMap">
    </collection>
  </resultMap>


到这里我们就配置好了一个两层嵌套的映射,为了得到权限信息,还需要修改SQL进行关联

<select id="selectAllUserAndRolesAndPrivileges" resultMap="userRoleAndPrivilegeListMap">
      select 
        u.id, 
        u.user_name, 
          u.user_password,
          u.user_email,
          u.user_info,
          u.head_img,
          u.create_time,
          r.id sysRole_id,
      r.role_name sysRole_role_name, 
      r.enabled sysRole_enabled,
      r.create_by sysRole_create_by,
      r.create_time sysRole_create_time,
      p.id sysRole_privilege_id,
      p.privilege_name sysRole_privilege_privilege_name,
      p.privilege_url sysRole_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_privilege表中的别名。因为sys_privilege嵌套在rolePrivilegeListMap中,前缀名是 privilege_

20180503075900421.png

20180503075136136.png

而rolePrivilegeListMap的前缀是sysRole_


2018050306123091.png


所以rolePrivilegeListMap中的privilegeMap的前缀就变测过了 sysRole_privilege_

在嵌套中,这个前缀需要叠加,一定不要写错,所以SQL如下


2018050308085285.png


单元测试

@Test
  public void selectAllUserAndRolesAndPrivilegesTest() {
    logger.info("selectAllUserAndRolesAndPrivilegesTest");
    // 获取SqlSession
    SqlSession sqlSession = getSqlSession();
    try {
      // 获取UserMapper接口
      UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
      // 调用selectAll,查询全部用户
      List<SysUser> userList = userMapper.selectAllUserAndRolesAndPrivileges();
      // 结果不为空
      Assert.assertNotNull(userList);
      // 结果大于0
      Assert.assertTrue(userList.size() > 0);
      logger.info("userList总数为:" + userList.size());
      for (SysUser sysUser : userList) {
        logger.info("用户名:" + sysUser.getUserName());
        for (SysRole sysRole : sysUser.getRoleList()) {
          logger.info("\t角色名:" + sysRole.getRoleName());
          for (SysPrivilege sysPrivilege : sysRole.getPrivilegeList()) {
            logger.info("\t\t权限名:" + sysPrivilege.getPrivilegeName());
          }
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      sqlSession.close();
      logger.info("sqlSession close successfully ");
    }
  }


Assert.assertNotNull(userList); 加个断点,debug看下数据


20180503081246415.png


日志

2018-05-02 20:10:08,202  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-05-02 20:10:08,207  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-05-02 20:10:08,211  INFO [main] (UserMapperTest.java:1164) - selectAllUserAndRolesAndPrivilegesTest
2018-05-02 20:10:08,287 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.user_info, u.head_img, u.create_time, r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time, p.id sysRole_privilege_id, p.privilege_name sysRole_privilege_privilege_name, p.privilege_url sysRole_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 
2018-05-02 20:10:08,411 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 
2018-05-02 20:10:08,448 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time, sysRole_privilege_id, sysRole_privilege_privilege_name, sysRole_privilege_privilege_url
2018-05-02 20:10:08,449 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0, 1, 用户管理, /users
2018-05-02 20:10:08,466 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0, 3, 系统日志, /logs
2018-05-02 20:10:08,468 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 1, 管理员, 1, 1, 2018-04-13 21:12:46.0, 2, 角色管理, /roles
2018-05-02 20:10:08,469 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 4, 人员维护, /persons
2018-05-02 20:10:08,473 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 5, 单位维护, /companies
2018-05-02 20:10:08,475 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 4, 人员维护, /persons
2018-05-02 20:10:08,477 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0, 5, 单位维护, /companies
2018-05-02 20:10:08,478 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 7
2018-05-02 20:10:08,479  INFO [main] (UserMapperTest.java:1177) - userList总数为:2
2018-05-02 20:10:08,479  INFO [main] (UserMapperTest.java:1179) - 用户名:admin
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1181) -   角色名:管理员
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1183) -     权限名:用户管理
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1183) -     权限名:系统日志
2018-05-02 20:10:08,482  INFO [main] (UserMapperTest.java:1183) -     权限名:角色管理
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1181) -   角色名:普通用户
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1183) -     权限名:人员维护
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1183) -     权限名:单位维护
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1179) - 用户名:artisan
2018-05-02 20:10:08,483  INFO [main] (UserMapperTest.java:1181) -   角色名:普通用户
2018-05-02 20:10:08,484  INFO [main] (UserMapperTest.java:1183) -     权限名:人员维护
2018-05-02 20:10:08,484  INFO [main] (UserMapperTest.java:1183) -     权限名:单位维护
2018-05-02 20:10:08,485  INFO [main] (UserMapperTest.java:1191) - sqlSession close successfully 


collection集合的嵌套查询


同association关联的嵌套查询这种方式类似,collection也会执行额外的SQL查询。 后续单开篇介绍。

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
4月前
|
SQL XML Java
菜鸟之路Day35一一Mybatis之XML映射与动态SQL
本文介绍了MyBatis框架中XML映射与动态SQL的使用方法,作者通过实例详细解析了XML映射文件的配置规范,包括namespace、id和resultType的设置。文章还对比了注解与XML映射的优缺点,强调复杂SQL更适合XML方式。在动态SQL部分,重点讲解了`&lt;if&gt;`、`&lt;where&gt;`、`&lt;set&gt;`、`&lt;foreach&gt;`等标签的应用场景,如条件查询、动态更新和批量删除,并通过代码示例展示了其灵活性与实用性。最后,通过`&lt;sql&gt;`和`&lt;include&gt;`实现代码复用,优化维护效率。
289 5
|
6月前
|
SQL XML Java
七、MyBatis自定义映射resultMap
七、MyBatis自定义映射resultMap
152 6
|
6月前
|
Java 数据库连接 mybatis
MyBatis篇-映射关系(1-1 1-n n-n)
本文介绍了MyBatis中四种常见关系映射的配置方法,包括一对一、一对多、多对一和多对多。**一对一**通过`resultMap`实现属性与字段的映射;**一对多**以用户-角色为例,使用`&lt;collection&gt;`标签关联集合数据;**多对一**以作者-博客为例,利用`&lt;association&gt;`实现关联;**多对多**则通过引入第三方类(如UserForDept)分别在User和Dept类中添加集合属性,并配置对应的`&lt;collection&gt;`标签完成映射。这些方法解决了复杂数据关系的处理问题,提升了开发效率。
|
8月前
|
XML Java 数据库连接
Mybatis一对一,一对多关联查询
## MyBatis一对一、一对多关联查询详解 MyBatis是一款优秀的持久层框架,提供了灵活的SQL映射功能,支持复杂的数据库操作。本文将详细介绍MyBatis中一对一和一对多关联查询的实现。 ### 一对一关联查询 一对一关联关系指的是一个表中的一条记录与另一个表中的一条记录相关联。例如,一个用户有一个地址信息。 #### 数据库表设计 假设有两个表:`user`和 `address`。 ``` CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50) ); CREATE TABLE address
201 18
|
9月前
|
XML Java 数据库连接
Mybatis映射关系
简介:本文介绍了MyBatis框架中四种常见的关系映射方式,包括一对一、一对多、多对一及多对多。一对一通过简单属性映射实现;一对多通过在主对象中添加集合属性并使用`&lt;collection&gt;`标签映射子对象集合;多对一则利用`&lt;association&gt;`标签在主对象中映射单个子对象;多对多需引入第三方类,分别在两个主对象中添加对方的集合属性,并通过`&lt;collection&gt;`标签实现映射。
152 32
|
10月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
SQL 缓存 Java
mybatis 一对多查询
mybatis 一对多查询
280 0
|
12月前
|
SQL XML Java
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
|
11月前
|
SQL XML Java
Mybatis中一对一和一对多的处理
这篇文章讲解了在Mybatis中如何处理一对一和一对多的关系映射,包括使用association和collection标签的具体方法。
282 1
|
Java 数据库连接 mybatis
后端框架的学习----mybatis框架(9、多对一处理和一对多处理)
这篇文章介绍了在MyBatis框架中如何处理多对一和一对多的关联查询,通过定义`<resultMap>`和使用`<association>`与`<collection>`元素来实现对象间的关联映射。