Mybatis延迟加载

Mybatis延迟加载

假设现在有1个用户,这个账户关联100个用户,当我们查询用户时,需不需要加载用户所关联的账户呢?
而查询账户户时,用不用查询用户呢?

答:在查询用户时,我们希望使用账户数据的时候,再去查询
在查询账户时,我们应该知道这个账户所属的用户信息

所以,我们可以得出延迟加载的概念:
延迟加载:在真正使用数据的时候才发起查询,不用的时候不查询关联的数据,延迟加载又叫按需查询(懒加载)
立即加载:不管用不用,只要一调用方法,马上发起查询。
使用场景:在对应的四种表关系中,一对多、多对多通常情况下采用延迟加载,多对一、一对一通常情况下采用立即加载。

理解了延迟加载的基本概念后,我们来看一下如何在Mybatis中使用延迟加载:
我们在Mybatis的官方文档中可以看到通过使用 settings标签下的 lazyLoadingEnabled 和 aggressiveLazyLoading 标签可以开启延迟加载和立即加载.

代码演示:

1.SQL语句

      //创建用户表和账户表
      CREATE TABLE USER(
	id INT PRIMARY KEY AUTO_INCREMENT,
	 username VARCHAR(32) NOT NULL,
	 birthday DATE NOT NULL,
	 sex VARCHAR(32) NOT NULL,
	 address VARCHAR(32) NOT NULL
      );
      CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT,
	uid INT NOT NULL,
	money DOUBLE NOT NULL,
	FOREIGN KEY (uid) REFERENCES USER(id)
      );

2.Java代码

      //创建用户和账户的实体类
      //这里使用了lombok插件来生成getter和setter方法
      @Data
      public class User {
          private Integer id;
          private String username;
          private Date birthday;
          private String sex;
          private String address;
          private List<Account> accountList;
      }
      
      @Data
      public class Account {
          private Integer id;
          private Integer uid;
          private Double money;
      }
    

注意因为我们是查找用户的同时查找出其所拥有的账户所以我们需要在用户类中增加账户的集合的属性,用来封装返回的结果。
3.UserMapper接口

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

4.在UserMapper.xml中绑定UserMapper接口并配置findAll方法的映射

      <mapper namespace="com.gaoteng.dao.UserMapper">
    <resultMap id="userAccountMap" type="user">
        <id column="id" property="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="accountList" column="id" select="Account.findUserByUid" ofType="account">
        </collection>
    </resultMap>
  <select id="findAll" resultMap="userAccountMap">
    select * from user
  </select>

</mapper>

主要的功能实现位于 中,对于账户列表的信息通过collection集合来映射,通过select指定集合中的每个元素如何查询,在本例中select的属性值为AccountMapper.xml文件的namespace com.gaotng.dao.AccountMapper路径以及指定该映射文件下的findAllByUid方法,通过这个唯一标识指定集合中元素的查找方式。因为在这里需要用到根据用户ID查找账户,所以需要同时配置一下findAllByUid方法的实现。

5.配置AccountMapper接口以及AccountMapper.xml

     public interface AccountMapper {
    /**
     * 根据uid查询账户信息
     */
    List<Account> findUserByUid(@Param("uid") Integer uid);


      <mapper namespace="com.gaoteng.dao.AccountMapper">
          <select id="findUserByUid" resultType="account">
              select * from account where uid = #{uid}
          </select>
      </mapper>  
}

6.在Mybatis的核心配置文件中开启全局延迟加载

<?xml version="1.0" encoding="GBK" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--引入外部配置文件-->
    <properties resource="db.properties"/>
    <settings>
        <!--开启驼峰命名自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--启用日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--启用二级缓存-->
        <setting name="cacheEnabled" value="true"/>
        <!--开启全局延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--关闭立即加载(默认关闭)-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <typeAliases>
        <!--类型别名-->
        <package name="com.gaoteng.domain"/>
    </typeAliases>


    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--<mapper resource="com/gaoteng/dao/UserMapper.xml"/>-->
        <package name="com.gaoteng.dao"/>
    </mappers>
</configuration>

7.测试

      public class MapperTest {

    @Test
    public void test1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> all = mapper.findAll();
//        for (User user : all) {
//            System.out.println(user);
//        }

        sqlSession.close();
    }

}

测试说明:当我们注释了findAllTest()方法中的for循环打印的时候,我们将不会需要用户的账户信息,按照延迟加载的特性程序只会查询用户的信息,而不会查询账户的信息。当我我们放开for循环打印的时候我们使用到了用户和账户的信息,程序会同时将用户以及对应的账户信息打印出来。

当注释for循环时,

没有注释for循环时:

本篇博客参考以下文章:
Mybatis延迟加载的实现以及使用场景

特别感谢!!!

posted @ 2020-05-10 21:57  毕竟是曾经  阅读(441)  评论(0编辑  收藏  举报