深入理解什么是Mybatis懒加载(延迟加载)

 更新时间:2023年10月27日 10:39:46   作者:秦怀  
这篇文章主要介绍了深入理解什么是Mybatis懒加载(延迟加载),mybatis的懒加载,也称为延迟加载,是指在进行关联查询的时候,按照设置延迟规则推迟对关联对象的select查询,延迟加载可以有效的减少数据库压力,需要的朋友可以参考下

mybatis懒加载

mybatis的懒加载,也称为延迟加载,是指在进行关联查询的时候,按照设置延迟规则推迟对关联对象的select查询,延迟加载可以有效的减少数据库压力。

延迟加载只对关联对象有延迟设置,主加载对象都是直接执行查询语句的

关联对象加载类型

mybatis的关联对象的查询select语句的执行时机,可以分为3类,直接加载,侵入式加载与深度延迟加载。

1.直接加载

执行完主加载对象的select语句,马上就会执行关联对象的select语句。

2.侵入式延迟加载

执行对主加载对象的查询时,不会执行关联对象的查询,但是当访问主加载对象的详情时,就会马上执行关联对象的select查询,也就是说关联对象的查询执行,侵入到了猪价在对象的详情访问中,可以理解为,将关联对象的详情侵入到主加载对象的详情中,作为它的一部分出现了。

3.深度延迟加载

执行对主加载对象的查询的时候,不会执行对关联对象的查询,访问主加载对象的详情的时候,也不会执行关联对象的select查询,只有当真正的访问关联对象的详情的时候,才会执行对关联对象的select查询。

注意:延迟加载的最基本要求,关联对象的查询与主加载对象的查询必须是分别放在两个语句中的,不能使用多表连接查询,因为多表连接查询相当于把多张表连接成一张表的查询,无法做到分开查询,会一次性将表的内容查询出来。 延迟加载,可以应用到一对多,一对一,多对一,多对多的关联查询中。

举个例子:我们只用上一个demo,查询minister与country之间的关系,数据库如下:

#创建数据库
CREATE DATABASE `test` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
#创建数据表
CREATE TABLE `test`.`student` ( `sid` INT(10) NOT NULL AUTO_INCREMENT ,`sname` VARCHAR(20) NOT NULL ,PRIMARY KEY(`sid`)) ENGINE = MyISAM;
CREATE TABLE `test`.`course` ( `cid` INT(10) NOT NULL AUTO_INCREMENT ,`cname` VARCHAR(20) NOT NULL ,PRIMARY KEY(`cid`)) ENGINE = MyISAM;
CREATE TABLE `test`.`middle` (
`id` INT(10) NOT NULL AUTO_INCREMENT ,`studentId` INT(10) NOT NULL ,`courseId` INT(10) NOT NULL ,PRIMARY KEY(`id`)) ENGINE = MyISAM;
#初始化数据表
INSERT INTO `course` (`cid`, `cname`) VALUES ('1', 'JAVA') ;
INSERT INTO `course` (`cid`, `cname`) VALUES ('2', 'C++') ;
INSERT INTO `course` (`cid`, `cname`) VALUES ('3', 'JS') ;

INSERT INTO `student` (`sid`, `sname`) VALUES ('1', 'Jam') ;
INSERT INTO `student` (`sid`, `sname`) VALUES ('2', 'Lina') ;

INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('1', '1', '1');
INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('2', '1', '2');
INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('3', '2', '1');
INSERT INTO `middle` (`id`, `studentId`, `courseId`) VALUES ('4', '2', '3');

与之对应的实体类:Country.class

public class Country {
	private Integer cid;
	private String cname;

	private Set<Minister> ministers;
	public Integer getCid() {
		return cid;
	}
	public void setCid(Integer cid) {
		this.cid = cid;
	}
	public String getName() {
		return cname;
	}
	public void setName(String cname) {
		this.cname = cname;
	}
	public Set<Minister> getMinisters() {
		return ministers;
	}
	public void setMinisters(Set<Minister> ministers) {
		this.ministers = ministers;
	}
	@Override
	public String toString() {
		return "Country [cid=" + cid + ", cname=" + cname + ", ministers="
				+ ministers + "]";
	}
}

Minister.class

public class Minister {
	private Integer mid;
	private String mname;
	@Override
	public String toString() {
		return "Minister [mid=" + mid + ", mname=" + mname + "]";
	}
	public Integer getMid() {
		return mid;
	}
	public void setMid(Integer mid) {
		this.mid = mid;
	}
	public String getMname() {
		return mname;
	}
	public void setMname(String mname) {
		this.mname = mname;
	}
	
}

主配置文件mybatis.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>
    <!-- 配置数据库文件 -->
    <properties resource="jdbc_mysql.properties">

    </properties>
    <settings>
        <setting name="lazyLoadingEnabled" value="false"/>
        <!--<setting name="aggressiveLazyLoading" value="false"/>-->
    </settings>
    <!-- 别名,对数据对象操作全名太长,需要使用别名 -->
    <typeAliases>
        <!--<typeAlias type="bean.Student" alias="Student"/>-->
        <!--直接使用类名即可,对于整个包的路径配置(别名),简单快捷 -->
        <package name="beans"/>
    </typeAliases>
    <!-- 配置运行环境 -->
    <!-- default 表示默认使用哪一个环境,可以配置多个,比如开发时的测试环境,上线后的正式环境等 -->
    <environments default="mysqlEM">
        <environment id="mysqlEM">
            <transactionManager type="JDBC">
            </transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 注册映射文件 -->
    <mappers>
        <mapper resource="mapper/mapper.xml"/>
    </mappers>
</configuration>

mapper.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="dao.ICountryDao">
    <!-- 	resultMap 能解决字段和属性不一样的问题 -->
    <!-- 以后用得比较多 ,是因为可以使用延迟加载-->
    <!-- 嵌套查询 -->
    <select id="selectMinisterByCountry" resultType="Minister">
	select mid,mname from minister where countryId=#{ooo}
	</select>
    <resultMap type="Country" id="countryMapper">
        <id column="cid" property="cid"/>
        <result column="cname" property="cname"/>
        <!-- country中有一个成员变量是ministers,它的泛型是Minister -->
        <collection property="ministers"
                    ofType="Minister"
                    select="selectMinisterByCountry"
                    column="cid">
        </collection>
    </resultMap>
    <select id="selectCountryById" resultMap="countryMapper">
		select cid,cname
		from country
		where
		cid=#{cid}
	</select>
</mapper>

与之对应的sql接口:

public interface ICountryDao {
	Country selectCountryById(int cid);
}

使用到的工具类:

public class MyBatisUtils {
  private static SqlSessionFactory sqlSessionFactory;

  public static SqlSession getSqlSession() {
    InputStream is;
    try {
      is = Resources.getResourceAsStream("mybatis.xml");
      if (sqlSessionFactory == null) {
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      }
      return sqlSessionFactory.openSession();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return null;
  }
}

直接加载查询

关于懒加载的配置,我们只需要在mybatis.xml文件里面使用就可以了,懒加载有一个总开关,lazyloadingEnabled,只要置为false就可以将延迟加载关掉,那就是直接加载查询了。配置在与之间。

    <properties resource="jdbc_mysql.properties">
    </properties>
    <settings>
        <setting name="lazyLoadingEnabled" value="flase"/>
    </settings>
    <!-- 别名,对数据对象操作全名太长,需要使用别名 -->
    <typeAliases>
        <!--<typeAlias type="bean.Student" alias="Student"/>-->
        <!--直接使用类名即可,对于整个包的路径配置(别名),简单快捷 -->
        <package name="bean"/>
    </typeAliases>

当单元测试是直接査country对象的时候:

	@Test
	public void TestselectCountryById(){
		Country country=dao.selectCountryById(1);
	}

结果是,我们可以看到两条sql,除了查询country之外,连同minister关联对象也一起查询了,这就是直接加载,简单粗暴,不管是否使用,都会先将关联查询加载:

[service] 2018-07-17 09:59:00,796 - dao.ICountryDao.selectCountryById -491  [main] DEBUG dao.ICountryDao.selectCountryById  - ==>  Preparing: select cid,cname from country where cid=? 
[service] 2018-07-17 09:59:00,823 - dao.ICountryDao.selectCountryById -518  [main] DEBUG dao.ICountryDao.selectCountryById  - ==> Parameters: 1(Integer)
[service] 2018-07-17 09:59:00,838 - dao.ICountryDao.selectMinisterByCountry -533  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ====>  Preparing: select mid,mname from minister where countryId=? 
[service] 2018-07-17 09:59:00,838 - dao.ICountryDao.selectMinisterByCountry -533  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ====> Parameters: 1(Integer)
[service] 2018-07-17 09:59:00,849 - dao.ICountryDao.selectMinisterByCountry -544  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - <====      Total: 2
[service] 2018-07-17 09:59:00,850 - dao.ICountryDao.selectCountryById -545  [main] DEBUG dao.ICountryDao.selectCountryById  - <==      Total: 1

侵入式延迟加载

需要将延迟加载开关开启(true),同时也需要将侵入式加载开关开启(true)

    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressivelazyLoading" value="true"/>
    </settings>

1.当我们只查询country的时候,只会执行country的查询,不会执行关联查询minister:

	@Test
	public void TestselectCountryById(){
		Country country=dao.selectCountryById(1);
	}

结果如下,只有一条sql:

[service] 2018-07-17 14:30:55,471 - dao.ICountryDao.selectCountryById -902  [main] DEBUG dao.ICountryDao.selectCountryById  - ==>  Preparing: select cid,cname from country where cid=? 
[service] 2018-07-17 14:30:55,494 - dao.ICountryDao.selectCountryById -925  [main] DEBUG dao.ICountryDao.selectCountryById  - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:30:55,590 - dao.ICountryDao.selectCountryById -1021 [main] DEBUG dao.ICountryDao.selectCountryById  - <==      Total: 1

当我们查询country的属性,但是不是minister属性的时候:

	@Test
	public void TestselectCountryById(){
		Country country=dao.selectCountryById(1);
		System.out.println(country.getCid());
	}

结果如下,会加载到关联对象minister,这就是侵入式延迟加载:

[service] 2018-07-17 14:32:37,959 - dao.ICountryDao.selectCountryById -724  [main] DEBUG dao.ICountryDao.selectCountryById  - ==>  Preparing: select cid,cname from country where cid=? 
[service] 2018-07-17 14:32:37,979 - dao.ICountryDao.selectCountryById -744  [main] DEBUG dao.ICountryDao.selectCountryById  - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:32:38,170 - dao.ICountryDao.selectCountryById -935  [main] DEBUG dao.ICountryDao.selectCountryById  - <==      Total: 1
[service] 2018-07-17 14:32:38,171 - dao.ICountryDao.selectMinisterByCountry -936  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ==>  Preparing: select mid,mname from minister where countryId=? 
[service] 2018-07-17 14:32:38,171 - dao.ICountryDao.selectMinisterByCountry -936  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:32:38,173 - dao.ICountryDao.selectMinisterByCountry -938  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - <==      Total: 2

深度延迟加载

需要将延迟加载开关开启(true),同时需要将侵入式加载开关关闭(false)

    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressivelazyLoading" value="false"/>
    </settings>

1.当我们只查询出country的时候,只会查询country,而不会查询minister: 单元测试代码:

	@Test
	public void TestselectCountryById(){
		Country country=dao.selectCountryById(1);
	}

[service] 2018-07-17 14:20:38,608 - dao.ICountryDao.selectCountryById -1271 [main] DEBUG dao.ICountryDao.selectCountryById  - ==>  Preparing: select cid,cname from country where cid=? 
[service] 2018-07-17 14:20:38,631 - dao.ICountryDao.selectCountryById -1294 [main] DEBUG dao.ICountryDao.selectCountryById  - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:20:38,980 - dao.ICountryDao.selectCountryById -1643 [main] DEBUG dao.ICountryDao.selectCountryById  - <==      Total: 1

2.当我们访问country的属性的时候,也不会加载关联查询的minister:

	@Test
	public void TestselectCountryById(){
		Country country=dao.selectCountryById(1);
		System.out.println(country.getCid());
	}

结果同样是:

[service] 2018-07-17 14:24:03,004 - org.apache.ibatis.transaction.jdbc.JdbcTransaction -686  [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction  - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@cb51256]
[service] 2018-07-17 14:24:03,030 - dao.ICountryDao.selectCountryById -712  [main] DEBUG dao.ICountryDao.selectCountryById  - ==>  Preparing: select cid,cname from country where cid=? 
[service] 2018-07-17 14:24:03,078 - dao.ICountryDao.selectCountryById -760  [main] DEBUG dao.ICountryDao.selectCountryById  - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:24:03,160 - dao.ICountryDao.selectCountryById -842  [main] DEBUG dao.ICountryDao.selectCountryById  - <==      Total: 1

3.当我们查询country属性minister的时候:

	@Test
	public void TestselectCountryById(){
		Country country=dao.selectCountryById(1);
		System.out.println(country.getMinisters());
	}

我们可以看到结果,执行了minister的查询:

[service] 2018-07-17 14:26:55,913 - dao.ICountryDao.selectCountryById -1540 [main] DEBUG dao.ICountryDao.selectCountryById  - ==>  Preparing: select cid,cname from country where cid=? 
[service] 2018-07-17 14:26:55,943 - dao.ICountryDao.selectCountryById -1570 [main] DEBUG dao.ICountryDao.selectCountryById  - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:26:56,161 - dao.ICountryDao.selectCountryById -1788 [main] DEBUG dao.ICountryDao.selectCountryById  - <==      Total: 1
[service] 2018-07-17 14:26:56,162 - dao.ICountryDao.selectMinisterByCountry -1789 [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ==>  Preparing: select mid,mname from minister where countryId=? 
[service] 2018-07-17 14:26:56,163 - dao.ICountryDao.selectMinisterByCountry -1790 [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ==> Parameters: 1(Integer)
[service] 2018-07-17 14:26:56,168 - dao.ICountryDao.selectMinisterByCountry -1795 [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - <==      Total: 2
[Minister [mid=2, mname=bbb], Minister [mid=1, mname=aaa]]

来个表格~

加载方式lazyLoadingEnabledaggressiveLazyLoading
直接加载必须是false,默认是false不管是什么,只要lazyLoadingEnabled是false就是直接加载
侵入式延迟加载必须是true必须是true
深度延迟加载必须是true必须是false,默认是false

到此这篇关于深入理解什么是Mybatis懒加载(延迟加载)的文章就介绍到这了,更多相关Mybatis懒加载(延迟加载)内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中ConcurrentHashMap和Hashtable的区别

    Java中ConcurrentHashMap和Hashtable的区别

    ConcurrentHashMap 和 Hashtable 都是用于在Java中实现线程安全的哈希表数据结构的类,但它们有很多区别,本文就来详细的介绍一下,感兴趣的可以了解一下
    2023-10-10
  • tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列的解决办法

    tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列的解决办法

    tk.mybatis是一个很好用的通用插件,本文主要介绍了tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列的解决办法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Java中基于maven实现zxing二维码功能

    Java中基于maven实现zxing二维码功能

    这篇文章主要介绍了Java中基于maven实现zxing二维码功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02
  • 通过jxl.jar 读取、导出excel的实例代码

    通过jxl.jar 读取、导出excel的实例代码

    通过jxl.jar 读取、导出excel的实例代码,需要的朋友可以参考一下
    2013-03-03
  • Kotlin协程与并发深入全面讲解

    Kotlin协程与并发深入全面讲解

    Android官方对协程的定义-协程是一种并发设计模式,您可以在Android平台上使用它来简化异步执行的代码。协程是在版本1.3中添加到Kotlin的,它基于来自其他语言的既定概念
    2022-11-11
  • 在Spring Boot中如何使用Cookies详析

    在Spring Boot中如何使用Cookies详析

    这篇文章主要给大家介绍了关于在Spring Boot中如何使用Cookies的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-11-11
  • Java Swagger技术使用指南

    Java Swagger技术使用指南

    Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步
    2021-09-09
  • Mybatis中使用in()查询的方式详解

    Mybatis中使用in()查询的方式详解

    当参数有值,添加条件查询,附带一个字符串的in查询,下面这篇文章主要给大家介绍了关于Mybatis中使用in()查询的方式,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • Java IO流 文件传输基础

    Java IO流 文件传输基础

    这篇文章主要介绍了Java IO流 文件传输基础的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-07-07
  • java中JsonObject与JsonArray转换方法实例

    java中JsonObject与JsonArray转换方法实例

    在项目日常开发中常常会遇到JSONArray和JSONObject的转换,很多公司刚入职的小萌新会卡在这里,下面这篇文章主要给大家介绍了关于java中JsonObject与JsonArray转换方法的相关资料,需要的朋友可以参考下
    2023-04-04

最新评论