懒加载是为了改善在映射结果集解析对象属性时,大量的嵌套子查询的并发效率问题,当设置懒加载后,只有在使用指定属性时才会触发子查询,从而实现分散SQL请求的目的。

按照惯例,依然是先来看一个基础的使用示例:

public interface User2Mapper {

    User findWithLazyById(Integer id);
}
<resultMap id="lazyResultMap" type="com.wuwenze.mybatis.example.User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="age" column="age"/>

    <!-- 通过fetchType="lazy"配置当前子查询为懒加载 -->
    <association property="userGroup" fetchType="lazy" column="user_group_id" select="findUserGroupById" />
</resultMap>

<select id="findUserGroupById" parameterType="integer" resultType="com.wuwenze.mybatis.example.UserGroup">
    SELECT * FROM user_group WHERE id = #{id}
</select>


<select id="findWithLazyById" parameterType="integer" resultMap="lazyResultMap">
    SELECT * FROM user WHERE id = #{id}
</select>
@Test
public void test1() {
    final User user = user2Mapper.findWithLazyById(1);
    System.out.printf("获取基本属性:%s\n", user.getName());
    System.out.printf("获取配置了懒加载的属性:%s\n", user.getUserGroup());
}

//Opening JDBC Connection
//Created connection 482082765.
//Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1cbbffcd]
//==>  Preparing: SELECT * FROM user WHERE id = ?
//==> Parameters: 1(Integer)
//<==    Columns: id, name, age, user_group_id
//<==        Row: 1, Zhang, 30, 1
//<==      Total: 1
//获取基本属性:Zhang
//==>  Preparing: SELECT * FROM user_group WHERE id = ?
//==> Parameters: 1(Integer)
//<==    Columns: id, name
//<==        Row: 1, Administrators
//<==      Total: 1
//获取配置了懒加载的属性:UserGroup(id=1, name=Administrators)
//Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1cbbffcd]
//Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1cbbffcd]
//Returned connection 482082765 to pool.

从运行结果可以很清晰的看到,只有在使用user.getUserGroup()对象时,才会触发对应的子查询。

在嵌套子查询中,通过手动指定fetchType="lazy"即可设置懒加载,除了懒加载的属性本身,在调用equals(), clone(), hashCode(), toString()等函数时均会触发当前对象所有未执行的懒加载SQL。

此外,除了手动控制以外,亦可以通过全局mybatis参数进行控制。

  • lazyLoadingEnabled: 全局懒加载开关 (默认false)
  • aggressiveLazyLoading: 任意方法触发加载 (默认false)
<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

未完待续。。。