懒加载(延迟加载)


概述

延迟加载:在真正使用数据的时候才发起查询,不用的时候不查询关联的数据,延迟加载又叫按需查询(懒加载)
立即加载(积极加载):不管用不用,只要一调用方法,马上发起查询

使用及案例

案例简介:
一个用户下有多个账户
表关系:一对多
需求:查询所有用户的信息;需要时,查询该用户下的账户信息
案例分析:
需要两张表:user用户表,account账户表
需要两个实体类(pojo)
需要两个mapper接口(sql映射)
需要两个mapper映射的xml
实体类如下:
User.java 此处省略构造及get和set

public class User {
  private Integer id;
  private String username;
  private Date birthday;
  private String sex;
  private String address;

  List<Account> accounts;
}

Account.java 此处省略构造及get和set

public class Account {
  private Integer id;
  private Integer uId;
  private double money;

  private  User user;
}

mapper接口如下:
UserMapper.java

public interface UserMapper {
  /**
    * 查询所有用户信息
    * @return
    */
  List<User> findAll();
}

AccountMapper.java

public interface AccountMapper {
  /**
    * 根据id查询账户信息
    * @param id
    * @return
    */
  Account findById(int id);
}

配置SqlMapConfig.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>
       <!--开启懒加载(延迟加载)-->

        <!-- 将lazyLoadingEnable设置为 teue  启用延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        
        <!-- 将aggressiveLazyLoading设置为 false 将积极加载修改为消极加载-->
        <setting name="aggressiveLazyLoading" value="false"/>

        <!-- 指定对象的哪些方法触发一次延迟加载;默认值:equals,clone,hashCode,toString -->
        <!-- 注意:由于默认值toString方法会触发延迟加载,而打印对象信息会触发toString();所以这里将toString 方法排除,才可看到延迟加载的效果 -->
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode"/>
    </settings>
</configuration>

mapper映射文件
映射文件中resultMap标签的association和collection 具备延迟加载功能
UserMapper.xml文件

<!--属性`namespace`指向接口全限定名-->
<mapper namespace="cn.dy.mapper.UserMapper">
    <resultMap id="userAccount" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>

        <!-- collection 可以使用延迟加载,property为当前实体类的属性名,column为传递给延迟方法的参数,select为延迟方法的全名称(包名.类名.方法名),ofType为当前集合属性的类型(collection标签支持该属性)   -->
        <!-- association  ofType替换为javaType,javaType为当前属性的类型;其余用法相同,  javaType(association标签支持该属性) -->
        <collection property="accounts" column="id" select="cn.dy.mapper.AccountMapper.findById" ofType="account">
        </collection>
    </resultMap>

    <select id="findAll" resultMap="userAccount">
        SELECT id, username, birthday, sex, address
        FROM user
    </select>
</mapper>

AccountMapper.xml文件

<!--属性`namespace`指向接口全限定名-->
<mapper namespace="cn.dy.mapper.AccountMapper">

    <!-- 上方sql查询语句触发延迟加载时将调用下方sql并返回数据信息 -->
    <select id="findById" resultType="account" parameterType="java.lang.Integer">
        SELECT id, money, UID FROM account
        <where>UID = #{id}</where>
    </select>
</mapper>

测试
TestUser.java

public class TestUser {
    private InputStream inputStream;
    private SqlSession sqlSession;
    private UserMapper userMapper;
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() {
        try {
            inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        //  这里的事务默认不开启
        sqlSession = sqlSessionFactory.openSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @After
    public void destory() {
        //  这里提交事务
        sqlSession.commit();
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        sqlSession.close();
    }

    // 查询所有的用户信息
    @Test
    public void testFindAll(){
        List<User> users = userMapper.findAll();
        for (User user : users) {
            System.out.println(user);

            // 这里调用getAccounts时会触发延迟加载,不调用时则不会触发延迟加载
            System.out.println(user.getAccounts());
            System.out.println("-----------------------------------------------");
        }
    }
}

使用场景

在对应的四种表关系中,一对多、多对多通常情况下采用延迟加载,多对一、一对一通常情况下采用立即加载


文章作者: zrh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 zrh !
  目录