MyBatis-延迟加载与MyBatis缓存(面试题)

MyBatis-延迟加载与MyBatis缓存(面试题)MyBatis-延迟加载与MyBatis缓存-概念性MyBatis-延迟加载与MyBatis缓存MyBatis-延迟加载与MyBatis缓存-概念性延迟加载(面试题)1、什么是延迟加载(按需加载)2、延迟加载MyBatis缓存(面试题)1、Cache缓存2、MyBatis缓存分析3、一级缓存4、二级缓存原理开启二级缓存5、禁用二级缓存6、刷新二级缓存延迟加载(面试题)1、什么是延迟加载(按需…

大家好,又见面了,我是你们的朋友全栈君。

MyBatis-延迟加载与MyBatis缓存-概念性

延迟加载(面试题)

1、什么是延迟加载(按需加载

 resultMap中的association(has a)和collection(has some)标签具有延迟加载的功能。
 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。需要关联信息时再去按需加载关联信息。这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

  • 设置延迟加载(配置问题使用代码演示)
    Mybatis默认是没开启延迟加载功能的,我们需要手动开启。
  • 需要在mybatis-config.xml文件中,在标签中开启延迟加载功能。
    lazyLoadingEnabled、aggressiveLazyLoading
    在这里插入图片描述
     在最新官方MyBatis文档里,有上面这2个属性,一个是延迟加载,一个是分层加载。
    lazyLoadingEnabled 默认值为false,那么在有级联关系的resultMap里,查询后会加载出所有的级联关系,当然有时候我们并不需要这些所有的时候,我们就可以应用到延迟加载给我们带来的好处了。
    aggressiveLazyLoading默认值是true,这里我称之为分层加载,大概意思是如果它为true,那么当我使用了延迟加载,要么所有级联都不加载,要么如果我加载一个,其他都得加载.
    aggressiveLazyLoading值是false 那么就是按需加载,如果是true表示只要使用一个级联对象,就全部加载!
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 全部配置
    在这里插入图片描述
  • 局部配置
     fetchType是可以注明在association 和 collection里的,选值为eager和lazy,就是为了方便我们结合aggressiveLazyLoading(false)来配合使用的,让延迟加载发挥到极致,即只加载我需要的!
    在这里插入图片描述
    如果全局和局部同时生效,那么就近原则,局部生效!

2、延迟加载

在这里插入图片描述
以下是resultMap对应的POJO

  • Student:
public class Student { 
   

	private Integer id;
	private String studentName;
	private String studentAge;

	private List studentHealthCards;
	private ParentOfStudent parentOfStudent;

	public Integer getId() { 
   
		return id;
	}

	public void setId(Integer id) { 
   
		this.id = id;
	}

	public String getStudentName() { 
   
		return studentName;
	}

	public void setStudentName(String studentName) { 
   
		this.studentName = studentName;
	}

	public String getStudentAge() { 
   
		return studentAge;
	}

	public void setStudentAge(String studentAge) { 
   
		this.studentAge = studentAge;
	}

	public List getStudentHealthCards() { 
   
		return studentHealthCards;
	}

	public void setStudentHealthCards(List studentHealthCards) { 
   
		this.studentHealthCards = studentHealthCards;
	}

	public ParentOfStudent getParentOfStudent() { 
   
		return parentOfStudent;
	}

	public void setParentOfStudent(ParentOfStudent parentOfStudent) { 
   
		this.parentOfStudent = parentOfStudent;
	}

	@Override
	public String toString() { 
   
		return "Student [id=" + id + ", studentName=" + studentName + ", studentAge=" + studentAge + "]";
	}

}
  • StudentHealthCard:
public class StudentHealthCard { 
   

	private Integer id;
	private Integer stu_id;
	private String name;
	private String message;

	public Integer getId() { 
   
		return id;
	}

	public void setId(Integer id) { 
   
		this.id = id;
	}

	public Integer getStu_id() { 
   
		return stu_id;
	}

	public void setStu_id(Integer stu_id) { 
   
		this.stu_id = stu_id;
	}

	public String getName() { 
   
		return name;
	}

	public void setName(String name) { 
   
		this.name = name;
	}

	public String getMessage() { 
   
		return message;
	}

	public void setMessage(String message) { 
   
		this.message = message;
	}

	@Override
	public String toString() { 
   
		return "StudentHealthCard [id=" + id + ", stu_id=" + stu_id + ", name=" + name + ", message=" + message + "]";
	}
}
  • ParentOfStudent:
public class ParentOfStudent { 
   

	private Integer id;
	private Integer stu_id;
	private String name;

	public Integer getId() { 
   
		return id;
	}

	public void setId(Integer id) { 
   
		this.id = id;
	}

	public Integer getStu_id() { 
   
		return stu_id;
	}

	public void setStu_id(Integer stu_id) { 
   
		this.stu_id = stu_id;
	}

	public String getName() { 
   
		return name;
	}

	public void setName(String name) { 
   
		this.name = name;
	}

	@Override
	public String toString() { 
   
		return "ParentOfStudent [id=" + id + ", stu_id=" + stu_id + ", name=" + name + "]";
	}
}
  • Mapper文件
<?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="com.mybatis.mapper.StudentMapper">

	<resultMap type="Student" id="stu">
		<id property="id" column="id" />
		<result property="studentName" column="studentName" />
		<result property="studentAge" column="studentAge" />
		<association property="parentOfStudent" column="id"
			select="selectOneParentOfStudent" fetchType="eager">
		</association>
		<collection property="studentHealthCards" column="id"
			ofType="Model.StudentHealthCard" 
			select="selectOneStudentHealthCard" fetchType="eager">
		</collection>
	</resultMap>
	
	<select id="selectOneStudent" resultMap="stu"> 
	    select * from student
		where id = #{ 
   id}		  
	</select>
	
	<select id="selectOneParentOfStudent" resultType="ParentOfStudent"> 
	    select * from
		parentofstudent where stu_id = #{ 
   id}		  
	</select>
	
	<select id="selectOneStudentHealthCard" resultType="StudentHealthCard"> 
	    select *
		from studenthealthcard where stu_id = #{ 
   id}		  
	</select>
	
</mapper>
  • 测试

  • 情况1:开启延迟加载,默认分层加载,不开启局部加载
    执行语句 Student student = sm.selectOneStudent(1);
    以下是运行结果:
    在这里插入图片描述
    执行语句:Student student = sm.selectOneStudent(1);
    student.getParentOfStudent();
    在这里插入图片描述
    这就是默认分层加载的后果,好的那么现在我把分层加载设置为false

  • 即情况2:开启延迟加载,分层加载false,不适用局部加载
    执行语句 Student student = sm.selectOneStudent(1);
    以下是运行结果:
    在这里插入图片描述
    执行语句:Student student = sm.selectOneStudent(1);
    student.getParentOfStudent();
    在这里插入图片描述
    好了 3条sql变成了2条

  • 情况3:就是使用fetchType的情况下,可以指明即使在延迟加载情况下也可以立即加载某个级联关系!

MyBatis缓存(面试题)

1、Cache缓存

在这里插入图片描述
缓存中有,先查询缓存。缓存中没有,那么查询数据库。这样的话不用每次都查询数据库。减轻数据库的压力。提高查询率!!!

第一次查询的时候,由于缓存中没有,那么去查询数据库返回给客户端。同时还会把这个次查询的数据放入缓存。
第二次查询同样的数据时候,发现缓存中曾经有查询过的数据,那么直接从缓存中读取。不必再次查询数据库,减轻数据库压力!

2、MyBatis缓存分析

 mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。
在这里插入图片描述
 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

&emsp;Mybatis的缓存,包括一级缓存和二级缓存
 一级缓存指的就是sqlsession,在sqlsession中有一个数据区域,是map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。
一级缓存是session级别的,同一个session! 1级缓存是系统自带,不需要手动开启!

 二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是二级缓存区域。二级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。二级缓存中的value,就是查询出的结果对象。
二级缓存,可以跨session!二级缓存是要配置,然后手动开启!

一级缓存是默认使用的。
 二级缓存需要手动开启。

Map<String,Object> key 缓存标志 Value 缓存的数据

3、一级缓存

在这里插入图片描述
 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
Mybatis默认支持一级缓存。

  • 测试1
@Test
	public void test1(){ 
   
		Student s1 = mapper.selectOneStudent(1);
		Student s2 = mapper.selectOneStudent(1);
		System.out.println(s1==s2);
	}
  • 测试2
@Test
	public void test1(){ 
   
		Student s1 = mapper.selectOneStudent(1);
		
		//session.commit();
		//session.clearCache();
		
		Student s2 = mapper.selectOneStudent(1);
		System.out.println(s1==s2);
	}
  • 应用
    正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
    一个service方法中包括很多mapper方法调用。
service{ 
   
        //开始执行时,开启事务,创建SqlSession对象

	    //第一次调用mapper的方法findUserById(1)
        //第二次调用mapper的方法findUserById(1),从一级缓存中取数据

       
        //方法结束,sqlSession关闭
}

第一次调用mapper的方法findUserById(1)
第二次调用mapper的方法findUserById(1),从一级缓存中取数据
如果是执行两次service调用查询相同的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。

4、二级缓存

原理

下图是多个sqlSession请求UserMapper的二级缓存图解。
在这里插入图片描述
二级缓存是mapper级别的。
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件(xml)中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存

开启二级缓存

Mybatis默认是没有开启二级缓存
 1.在核心配置文件myBatis-config.xml中加入以下内容(开启二级缓存总开关):
 在settings标签中添加以下内容:
在这里插入图片描述
&emsp2.在StudentMapper映射文件中,加入以下内容,开启二级缓存:
在这里插入图片描述
 3.实现序列化(持久化)
在这里插入图片描述
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。
缓存默认是存入内存中,但是如果需要把缓存对象存入硬盘那么久需要序列化(实体类要实现)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果该类存在父类,那么父类也要实现序列化。
在这里插入图片描述测试1:

@Test
	public void test2(){ 
   
		SqlSessionFactory factory = MyBatisUtil.getSqlSessionFactory();
		SqlSession session1 = factory.openSession();
		StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
		Student s1 = mapper1.selectOneStudent(1);
		System.out.println(s1);
		session1.close();
		
		SqlSession session2 = factory.openSession();
		StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
		Student s2 = mapper2.selectOneStudent(1);
		System.out.println(s2);
	}

测试2:
@Test

public void test2(){ 
   
		SqlSessionFactory factory = MyBatisUtil.getSqlSessionFactory();
		
		SqlSession session1 = factory.openSession();
		StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
		Student s1 = mapper1.selectOneStudent(1);
		System.out.println(s1);
		session1.close();
		SqlSession session2 = factory.openSession();
		StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
		s1.setStudentName("王二小");
		mapper2.updateStudent(s1);
		session2.commit();
		session2.close();
		
		SqlSession session3= factory.openSession();
		StudentMapper mapper3 = session3.getMapper(StudentMapper.class);
		Student s2 = mapper3.selectOneStudent(1);
		System.out.println(s2);
	}

根据SQL分析,确实是清空了二级缓存了

5、禁用二级缓存

该statement中设置useCache=false,可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存。
在这里插入图片描述

6、刷新二级缓存

 该statement中设置flushCache=true可以刷新当前的二级缓存,默认情况下如果是select语句,那么flushCache是false。如果是insert、update、delete语句,那么flushCache是true。
 如果查询语句设置成true,那么每次查询都是去数据库查询,即意味着该查询的二级缓存失效。
 如果查询语句设置成false,即使用二级缓存,那么如果在数据库中修改了数据,而缓存数据还是原来的,这个时候就会出现脏读。
在这里插入图片描述
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143645.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月21日 上午8:40
下一篇 2022年5月21日 上午8:40


相关推荐

  • futex函数_UNIX/LINUX

    futex函数_UNIX/LINUX引子在编译2.6内核的时候,你会在编译选项中看到[*]Enablefutexsupport这一项,上网查,有的资料会告诉你”不选这个内核不一定能正确的运行使用glibc的程序”,那futex是什么?和glibc又有什么关系呢?1.什么是FutexFutex是FastUserspacemuTexes的缩写,由HubertusFranke,MatthewKirkwo

    2026年2月10日
    3
  • 段式液晶_段式数码 电容 液晶

    段式液晶_段式数码 电容 液晶一 段式液晶BL55070驱动IC:I2C接口4X35断码显示,宽工作电压(2.5~5.5V),-20~70度,静态1/21/31/4背级输出,1/21/3偏置电压生产厂商:上海贝

    2022年8月1日
    6
  • 垃圾图像分类流程图yolov4-tiny_用python编写垃圾分类系统

    垃圾图像分类流程图yolov4-tiny_用python编写垃圾分类系统数据下载链接https://pan.baidu.com/s/1wr3h2Wc720uqUeIroTCIJA百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固,支持教育网加速,支持手机端。注册使用百度网盘即可享受免费存储空间https://pan.baidu.com/s/1wr3h2Wc720uqUeIroTCIJA提取码:mqic为什么要进行垃圾分类?当废物处理不当-时,就会发生回收污染-,就像回收带有油的比萨盒(堆肥)一样。或者当废物得到正确处理但未正确准备.

    2022年10月5日
    4
  • Git出现SSL certificate problem: unable to get local issuer certificate

    Git出现SSL certificate problem: unable to get local issuer certificate使用 Git 进行 Clone 或者 Pull 程序的时候会提示 nbsp SSL nbsp certificate nbsp problem nbsp unable nbsp to nbsp get nbsp local nbsp issuer nbsp certificate nbsp 这个是由于 Git 默认开启了 SSL 验证 关闭即可 解决方式 gitconfigglo sslVerifyfal 执行以上 git 命令 关闭 ssl 验证

    2026年3月18日
    2
  • PHP的几个常用加密函数

    PHP的几个常用加密函数

    2021年10月12日
    48
  • python(62):保留两位小数[通俗易懂]

    python(62):保留两位小数[通俗易懂]转载:https://blog.csdn.net/jiandanjinxin/article/details/77752297在C/C++语言对于整形数执行除法会进行地板除(舍去小数部分)。例如

    2022年7月5日
    28

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号