mybatis学习6

假设在RBAC权限系统中一个用户只能拥有一个角色。
数据表结构可查看mybatis学习2
1、一对一映射:
1)使用自动映射处理一对一关系
UserMapper:

package cn.linst.mapper;

import cn.linst.model.SysRole;
import cn.linst.model.SysUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    
    
    /**
     * 根据用户 id 获取用户信息和用户的角色信息
     * @param id
     * @return
     */
    SysUser selectUserAndRoleById(Long id);
    
}

SysUser:

package cn.linst.model;

import lombok.Getter;
import lombok.Setter;

import java.util.Date;

@Getter
@Setter
public class SysUser {
    
    

    private Long id;

    private String userName;

    private String userPassword;

    private String userEmail;

    private String userInfo;

    // byte[]这个类型一般对应数据库中的 BLOB、LONGVARBINARY 以及和二进制流有关的字段类型
    private byte[] headImg;

    private Date createTime;


    /**
     * 用户角色
     */
    private SysRole role;
}
<?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 namespace="cn.linst.mapper.UserMapper">
<!-- sys_role 查询列的别名都是“role" 前缀,通过这种方式将属性都映射到了 SysUser的role 属性上-->
<!-- Mybatis 会先查找 role 属性,如果存在role 属性就创建 role 对象,然后在 role 对象中继续查找 roleName ,将 role_name 的值绑定到 role 对象的 roleName 属性上。-->
    <select id="selectUserAndRoleById" resultType="cn.linst.model.SysUser">
      select
        u.id,
        u.user_name userName,
        u.user_password userPassword,
        u.user_email userEmail ,
        u.user_info userInfo ,
        u.head_img headImg,
        u.create_time createTime ,
        r.id "role.id" ,
        r.role_name "role.roleName",
        r.enabled "role.enabled",
        r.create_by "role.createBy",
        r.create_time "role.createTime"
      from sys_user u
      inner join sys_user_role ur on ur.user_id = u.id
      inner join sys_role r on r.id = ur.role_id
      where u.id = #{id}
    </select>

</mapper>

UserMapperTest:

package cn.linst;


import cn.linst.mapper.UserMapper;
import cn.linst.model.SysRole;
import cn.linst.model.SysUser;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;

import java.util.*;

public class UserMapperTest extends BaseMapperTest {
    
    	
 	@Test
    public void testSelectUserAndRoleById() {
    
    
        // 获取sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
    
    
            // 获 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户( id=1OO1L)
            SysUser user = userMapper.selectUserAndRoleById(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
    
    
            // 不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }
}

BaseMapperTest:

package cn.linst;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.BeforeClass;

import java.io.IOException;
import java.io.Reader;



public class BaseMapperTest {
    
    

    private static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public static void init () {
    
    
        try {
    
    
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException ex) {
    
    
            ex.printStackTrace();
        }
    }

    public SqlSession getSqlSession() {
    
    
        return sqlSessionFactory.openSession();
    }
}

运行测试用例:

 Preparing: select u.id, u.user_name userName, u.user_password userPassword, u.user_email userEmail , u.user_info userInfo , u.head_img headImg, u.create_time createTime , r.id "role.id" , r.role_name "role.roleName", r.enabled "role.enabled", r.create_by "role.createBy", r.create_time "role.createTime" from sys_user u inner join sys_user_role ur on ur.user_id = u.id inner join sys_role r on r.id = ur.role_id where u.id = ? 

2)使用 resultMap 配置一对一映射
除了使用 MyBatis 自动映 来处理一对一嵌套外,还可以在 XML 映射文件中配置结果映射。
也可以使用resultMap进行配置。
在UserMapper.xml 中增加如 resultMap 配置。
UserMapper.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 namespace="cn.linst.mapper.UserMapper">
    <resultMap id="userRoleMap" type="cn.linst.model.SysUser">
        <id property="id" column="id" />
        <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"/>
        <!-- role 相关属性 -->
        <result property="role.id" column="role_id"/>
        <result property="role.roleName" column="role name" />
        <result property="role.enabled" column="enabled" />
        <result property="role.createBy" column="create_by" />
        <result property="role.createTime" column="role_create_time" jdbcType="TIMESTAMP" />
    </resultMap>
</mapper>

在role 中的 property 配置部分使用"role"前缀。在column 部分, 为了避免不同表中存在相同的列, 所有可能重名的列都增加了"role"前
缀。
UserMapper:

package cn.linst.mapper;

import cn.linst.model.SysRole;
import cn.linst.model.SysUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    
    
 	 /**
     * 根据用户 id 获取用户信息和用户的角色信息
     * @param id
     * @return
     */
    SysUser selectUserAndRoleById2(Long id);
}

UserMapperTest:

package cn.linst;


import cn.linst.mapper.UserMapper;
import cn.linst.model.SysRole;
import cn.linst.model.SysUser;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;

import java.util.*;

public class UserMapperTest extends BaseMapperTest {
    
    
    
    @Test
    public void testSelectUserAndRoleById2() {
    
    
        // 获取sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
    
    
            // 获 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户( id=1OO1L)
            SysUser user = userMapper.selectUserAndRoleById2(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
    
    
            // 不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }
}

BaseMapperTest:

package cn.linst;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.BeforeClass;

import java.io.IOException;
import java.io.Reader;


public class BaseMapperTest {
    
    

    private static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public static void init () {
    
    
        try {
    
    
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException ex) {
    
    
            ex.printStackTrace();
        }
    }

    public SqlSession getSqlSession() {
    
    
        return sqlSessionFactory.openSession();
    }
}

运行测试用例:

Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.user_info, u.head_img, u.create_time, r.id role_id, r.role_name, r.enabled enabled, r.create_by create_by, r.create_time role_create_time from sys_user u inner join sys_user_role ur on ur.user_id = u.id inner join sys_role r on r.id = ur.role_id where u.id = ? 

注:
MyBati 是支持 resultMap 映射继承的。
如:userRoleMap继承userMap。

<?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 namespace="cn.linst.mapper.UserMapper">
    <resultMap id="userMap" type="cn.linst.model.SysUser">
        <id property="id" column="id" />
        <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>

    <resultMap id="userRoleMap" extends="userMap" type="cn.linst.model.SysUser">       
        <!-- role 相关属性 -->
        <result property="role.id" column="role_id"/>
        <result property="role.roleName" column="role_name" />
        <result property="role.enabled" column="enabled" />
        <result property="role.createBy" column="create_by" />
        <result property="role.createTime" column="role_create_time" jdbcType="TIMESTAMP" />
    </resultMap>

</mapper>

3)使用 resultMap 的association 标签配置一对一映射
在上面的配置基础上,修改userRoleMap。修改成association标签的配置方式,如下:

UserMapper.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 namespace="cn.linst.mapper.UserMapper">

<resultMap id="userRoleMap" extends="userMap" type="cn.linst.model.SysUser">
      <!-- role 相关属性 -->
      <association property="role" columnPrefix="role_" javaType="cn.linst.model.SysRole">
          <result property="id" column="role_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" />
      </association>
</resultMap>


 <select id="selectUserAndRoleById2" resultMap="userRoleMap" >
      select
        u.id,
        u.user_name,
        u.user_password,
        u.user_email,
        u.user_info,
        u.head_img,
        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
      from sys_user u
      inner join sys_user_role ur on ur.user_id = u.id
      inner join sys_role r on r.id = ur.role_id
      where u.id = #{id}
    </select>
注意 sys_role 相关列的别名,都已经改成了"role_"前缀,特别注意 role_name 增加前缀后为 role_role_name。

association 标签包含以下属性:

属性 描述
property 对应实体类中的属性名,必填项
javaType 属性对应的 Java 类型
resultMap 可以直接使用现有的 resultMap ,而不需要在这里配置。
columnPrefix 查询列的前缀,配置前缀后,在子标签配置 result 的column可以省略前缀。

UserMapperTest:依然使用上面的testSelectUserAndRoleById2方法。运行结果和原来一样。

package cn.linst;


import cn.linst.mapper.UserMapper;
import cn.linst.model.SysRole;
import cn.linst.model.SysUser;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;

import java.util.*;

public class UserMapperTest extends BaseMapperTest {
    
    
    @Test
    public void testSelectUserAndRoleById2() {
    
    
        // 获取sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
    
    
            // 获 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户( id=1OO1L)
            SysUser user = userMapper.selectUserAndRoleById2(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
    
    
            // 不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }
}

使用 association 配置时还可以使用 resultMap 属性配置成一个resultMap 映射, 一般情况下,如果使用 Mybatis 代码生成器 都会生成每个表对应实体的resultMap 配置。也可以手写一个resultMap。
将role提取到roleMap,然后在resultMap的id=roleMap。
如:
UserMapper.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 namespace="cn.linst.mapper.UserMapper">
    <resultMap id="userMap" type="cn.linst.model.SysUser">
        <id property="id" column="id" />
        <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>
       
    <resultMap id="roleMap" type="cn.linst.model.SysRole">
        <result property="id" column="role_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>

    <resultMap id="userRoleMap" extends="userMap" type="cn.linst.model.SysUser">
        <!-- role 相关属性 -->
        <association property="role" columnPrefix="role_" resultMap="roleMap">
        </association>
    </resultMap>

roleMap现在是写在UserMapper.xml中的,放在RoleMapper.xml更合理些。
需要注意:

RoleMapper.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 namespace="cn.linst.mapper.RoleMapper">

    <resultMap id="roleMap" type="cn.linst.model.SysRole">
        <result property="id" column="role_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>
</mapper>

UserMapper.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 namespace="cn.linst.mapper.UserMapper">
    <resultMap id="userMap" type="cn.linst.model.SysUser">
        <id property="id" column="id" />
        <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>

    <resultMap id="userRoleMap" extends="userMap" type="cn.linst.model.SysUser">
        <!-- role 相关属性 -->
        <association property="role" columnPrefix="role_" resultMap="cn.linst.mapper.RoleMapper.roleMap">
        </association>
    </resultMap>
</mapper>

MyBatis 默认会给 roleMap 添加 当前命名空间的前缀,代码如下:

resultMap="cn.linst.mapper.RoleMapper.roleMap"

4)association 标签的嵌套查询
association标签的嵌套查询常用的属性如下:

属性 描述
select 另一个映射查询的 id, MyBatis 会额外执行这个查询获取嵌套对象的结果
column 列名(或别名),将主查询中列的结果作为嵌套查询的 数,配置方式如column={propl=coll , prop2=col2}, propl prop2 将作为嵌套查询的参数。
fetchType 数据加载方式,可选值为 lazy eager ,分别为延迟加载和积极加载,这个配置会覆盖全局的 lazyLoadingEnabled 配置。

UserMapper.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 namespace="cn.linst.mapper.UserMapper">

<resultMap id="userRoleMapSelect" extends="userMap" type="cn.linst.model.SysUser">
        <!-- role 相关属性 -->
        <association property="role" column="{id=role_id}" select="cn.linst.mapper.RoleMapper.selectRoleById">
        </association>
    </resultMap>

    <select id="selectUserAndRoleByIdSelect" resultMap="userRoleMapSelect">
        select
            u.id,
            u.user_name,
            u.user_password,
            u.user_email,
            u.user_info ,
            u.head_img ,
            u.create_time ,
            ur.role_id
            from sys_user u
            inner join sys_user_role ur on u.id = ur.user_id
        where u.id = #{id}
    </select>
</mapper>

注意表关联中己经没有 sys_role ,因为我们不是通过 SQL 获取全部的信息。角色信息要通过配置的 selectRoleById 方法进行查询。
这个方法写在 RoleMapper.xml 中。

RoleMapper.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 namespace="cn.linst.mapper.RoleMapper">


    <resultMap id="roleMap" type="cn.linst.model.SysRole">
        <result property="id" column="role_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>
    
    <select id="selectRoleById" resultMap="roleMap">
        select * from sys_role where id = #{id}
    </select>
</mapper>

RoleMapper:

package cn.linst.mapper;


import cn.linst.model.SysRole;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface RoleMapper {
    
    
    SysRole selectRoleById(Long id);
}

UserMapper:

package cn.linst.mapper;

import cn.linst.model.SysRole;
import cn.linst.model.SysUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    
    
    SysUser selectUserAndRoleByIdSelect(Long id);
}

UserMapperTest:

package cn.linst;


import cn.linst.mapper.UserMapper;
import cn.linst.model.SysRole;
import cn.linst.model.SysUser;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;

import java.util.*;

public class UserMapperTest extends BaseMapperTest {
    
    
    @Test
    public void testSelectUserAndRoleByIdSelect() {
    
    
        // 获取sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
    
    
            // 获 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户( id=1OO1L)
            SysUser user = userMapper.selectUserAndRoleByIdSelect(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
    
    
            // 不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }
}

运行测试方法:
因为第一个 SQL 的查询结果只有一条,所以根据这一条数据的role_id 关联了另一个查询,因此执行了两次 SQL。

可能会出现N+1问题,主SQL 查询一次,查询出N条结果,这N条结果要各自执行一次查询。可以通过 association 标签的fetchType 属性的数据加载方式来解决这个方式。

需要把 fetchType 设置lazy。
将id="userRoleMapSelect"修改如下:在association增加一个fetchType=“lazy”。
UserMapper.xml:

    <resultMap id="userRoleMapSelect" extends="userMap" type="cn.linst.model.SysUser">
        <!-- role 相关属性 -->
        <association property="role" column="{id=role_id}" select="cn.linst.mapper.RoleMapper.selectRoleById" fetchType="lazy">
        </association>
    </resultMap>

testSelectUserAndRoleByIdSelect测试方法增加一行输出:

   	@Test
    public void testSelectUserAndRoleByIdSelect() {
    
    
        // 获取sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
    
    
            // 获 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户( id=1OO1L)
            SysUser user = userMapper.selectUserAndRoleByIdSelect(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            // 增加一行输出
            System.out.println("调用 user.getRole ()");
            Assert.assertNotNull(user.getRole());
        } finally {
    
    
            // 不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }

发现并没有在调用getRole的时候才嵌套sql。

DEBUG [main] - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.user_info , u.head_img , u.create_time , ur.role_id from sys_user u inner join sys_user_role ur on u.id = ur.user_id where u.id = ? 
DEBUG [main] - ==> Parameters: 1001(Long)
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time, role_id
TRACE [main] - <==        Row: 1001, test, 123456, test@testemail, <<BLOB>>, <<BLOB>>, 2020-06-01 00:00:00.0, 2
DEBUG [main] - ====>  Preparing: select * from sys_role where id = ? 
DEBUG [main] - ====> Parameters: 2(Long)
TRACE [main] - <====    Columns: id, role_name, enabled, create_by, create_time
TRACE [main] - <====        Row: 2, 普通用户, 1, 1, 2020-02-01 17:02:34.0
DEBUG [main] - <====      Total: 1
DEBUG [main] - <==      Total: 1
调用 user.getRole ()

这是因为在Mybatis的全局配置中,有一个参数为 aggressiveLazyLoading。当值为true时(默认为true),对任意延迟属性的调用会使带有延迟加载属性的对象完整加载。反之,每种属性都将按需加载。
sys_user 过后并给 SysUser 对象赋值时, 会调用该对象其他 属性的setter方法,这也会触发上述的规则,导致本该延迟加载的属性直接加载。为了避免这种情况,需要在mybatis-config.xml 中添加如下配置:
mybatis-config.xml :

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- 省略其他-->
    <settings>
        <!-- 其他配置-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
</configuration>

运行结果:

DEBUG [main] - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.user_info , u.head_img , u.create_time , ur.role_id from sys_user u inner join sys_user_role ur on u.id = ur.user_id where u.id = ? 
DEBUG [main] - ==> Parameters: 1001(Long)
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time, role_id
TRACE [main] - <==        Row: 1001, test, 123456, test@testemail, <<BLOB>>, <<BLOB>>, 2020-06-01 00:00:00.0, 2
DEBUG [main] - <==      Total: 1
调用 user.getRole ()
DEBUG [main] - ==>  Preparing: select * from sys_role where id = ? 
DEBUG [main] - ==> Parameters: 2(Long)
TRACE [main] - <==    Columns: id, role_name, enabled, create_by, create_time
TRACE [main] - <==        Row: 2, 普通用户, 1, 1, 2020-02-01 17:02:34.0
DEBUG [main] - <==      Total: 1

可以看到在调用 getRole()方法后才执行嵌套SQL 查询结果。

注:

MyBatis 延迟加载是通过动态代理实现的,当调用配直为延迟加载的属性方法时, 动态代理的操作会被触发,这些额外的操作就是通过 MyBatis的SqlSession去执行嵌套 SQL。由于在和某些框架集成时, SqlSession 的生命周期交给了框架来管理,因此当对象超出SqlSession 生命周期调用时,会由于链接关闭等问题而抛出异常 在和 Spring 集成时,要确保只能在 Service 层调用延迟加载的属性 当结果从 Service 层返回至 Controller 层时, 如果获取延迟加载的属性值,会因为 SqlSessio口已经关闭而抛出异常。

有些时候还是需要在触发某方法时将所有的数据都加载进来,但是己经将 aggressiveLazyLoading 设置为 false。Mybatis 仍然提供了参数 lazyLoadTriggerMethods 帮助解决这个问题。
lazyLoadTriggerMethods:
当调用配置中的方法时,加载全部的延迟加载数据。默认值为 equals、clone 、hashCode、toString。因此在使用默认值的情况下,只要调用其中一个方法就可以实现加载调用对象的全部数据。

    @Test
    public void testSelectUserAndRoleByIdSelect() {
    
    
        // 获取sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
    
    
            // 获 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户( id=1OO1L)
            SysUser user = userMapper.selectUserAndRoleByIdSelect(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            System.out.println("调用 user.equals(null)");
            user.equals(null);
            // 增加一行输出
            System.out.println("调用 user.getRole ()");
            Assert.assertNotNull(user.getRole());
        } finally {
    
    
            // 不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }

运行测试用例,输出:

DEBUG [main] - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.user_info , u.head_img , u.create_time , ur.role_id from sys_user u inner join sys_user_role ur on u.id = ur.user_id where u.id = ? 
DEBUG [main] - ==> Parameters: 1001(Long)
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time, role_id
TRACE [main] - <==        Row: 1001, test, 123456, test@testemail, <<BLOB>>, <<BLOB>>, 2020-01-01 00:00:00.0, 2
DEBUG [main] - <==      Total: 1
调用 user.equals(null)
DEBUG [main] - ==>  Preparing: select * from sys_role where id = ? 
DEBUG [main] - ==> Parameters: 2(Long)
TRACE [main] - <==    Columns: id, role_name, enabled, create_by, create_time
TRACE [main] - <==        Row: 2, 普通用户, 1, 1, 2020-02-01 17:02:34.0
DEBUG [main] - <==      Total: 1
调用 user.getRole ()

可以看到调用 equals 方法后就触发了延迟加载属性的查询。

猜你喜欢

转载自blog.csdn.net/tongwudi5093/article/details/114679262