Mybatis缓存

目录儿

  • 一级缓存
    • 测试代码
    • 溯源:一级缓存在哪儿?
  • 二级缓存
    • 开启二级缓存步骤
    • 测试代码:

一级缓存

mybatis默认开启一级缓存,是sqlSession级别的缓存,在操作数据库的时候,都要构建一个sqlSession对象,其对象内部有一个map接口,用来缓存结果数据。

在同一个sqlSession当中,执行完全一致的查询语句,会首先查询一级缓存,如果找到有对应的查询结果数据,则从缓存中读取数据,如果找不到,则去磁盘查DB,走磁盘IO,查到数据后,把结果数据写入一级缓存,返回给用户。

如果在两次查询之间执行了DML操作(Data Manipulation Language),则sqlSession会清空一级缓存,防止脏数据。
Mybatis缓存_第1张图片

测试代码

用两次查询到的对象相同来证明第二次查询的对象是第一次查询结果

@Test
public void test01(){
	TeacherMapper dao sqlSession.getMapper(TeacherMapper.class);
	//第一次读取,会发行sg1
	Teacher teacher dao.selectone(tno:"1001");
	System.out.println(teacher);
	System.0Ut.println("=============================");
	//第二此读取数据,不会发行sqL,直接从缓存中获取数据
	Teacher teacher1 dao.selectone(tno:"1001");
	System.out.println(teacher1);
	System.out.println(teacher==teacher1);
}

当两次查询中间增加一个DML操作:

@Test
public void test01(){
	TeacherMapper dao sqlSession.getMapper(TeacherMapper.class);
	//第一次读取,会发行sg1
	Teacher teacher dao.selectone(tno:"1001");
	System.out.println(teacher);
	System.0Ut.println("=============================");
	Teacher temp = new Teacher();
	temp.setTno("3001");
	temp.setTname("临时代课老师");
	dao.insertone(temp);
	sqlSession.commit();  // 插入操作会清空缓存
	System.0Ut.println("=============================");
	//第二此读取数据,不会发行sqL,直接从缓存中获取数据
	Teacher teacher1 dao.selectone(tno:"1001");
	System.out.println(teacher1);
	System.out.println(teacher==teacher1);
}

因此第两次查询到的对象不是同一个。

一级缓存是相对于同一个sqlSession而言的,不用sqlSession的查询无法共享缓存。

溯源:一级缓存在哪儿?

Mybatis缓存_第2张图片
其中可以看到默认开启了缓存
Mybatis缓存_第3张图片

二级缓存

因为一级缓存是在同一个sqlSession中才有效,但很多场景是多个sqlSession并发工作,二级缓存就是为了解决这个问题。

二级缓存是基于Mappernamespace)级别的缓存,对于同一个Mapper文件不同sqlSession对象,可以共享缓存中的内容。
Mybatis缓存_第4张图片

二级缓存默认是不开启的,需要手动开启。

只有当一级缓存,SqlSession对象使用完毕后能够关闭时,二级缓存才能正常命中,否则将会出现缓存命中为零的现象。

开启二级缓存步骤

  1. application配置文件中指定mybatisxml 配置文件路径
    Mybatis缓存_第5张图片

  2. mybatisxml 配置文件路径,设置开启缓存:
    Mybatis缓存_第6张图片

    
    DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	
    	<settings>
        	
        	<setting name="cacheEnabled"             value="true"   />
        	
        	<setting name="useGeneratedKeys"         value="true"   />
        	
        	<setting name="defaultExecutorType"      value="SIMPLE" />
    		
        	<setting name="logImpl"                  value="SLF4J"  />
        	
    		
    	settings>	
    configuration>
    
  3. 为具体的Mapper映射文件的命名空间进行二级缓存的具体配置。
    Mybatis缓存_第7张图片

    
    <cache 
    	type="org.apache.ibatis.cache.impl.PerpetualCache"
    	eviction= "LRU" 
    	flushInterval= "100000" 
    	readOnly= "true" 
    	size= "1024"/>
    

    也可以简单配置使用默认参数

    <cache/>
    
    • eviction代表缓存回收策略,目前mybatis提供以下回收策略:
      • LRU(Least Recently Used):最近最少使用的,回收最长时间不用的对象;
      • FIFO(First in first out):先进先出,按照对象进入缓存的顺序来移除;
      • SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象;
      • WEAK:弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。
    • flushInterval:缓存刷新时间间隔,单位为毫秒,每经过相应时间会对缓存进行刷新,如果没有配置,当SQL被执行的时候才会刷新缓存。
    • readOnly:只读,设置只读为“true”意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是没有办法修改缓存,它的默认值是false,不允许修改。
    • size:引用数目,是一个整数,代表缓存最多可以存储多少的对象,该数据不宜设置过大,如果设置过大会导致内存溢出。
    • type:缓存类型,默认使用mybatis提供的PerpetualCache,也可以指定第三方缓存。
  4. 使缓存对象的实体类实现序列化接口(Serializable
    由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,实现序列化接口的目是二级缓存可能会使用硬盘临时存储,所以要实现序列化接口保证对象能够被序列化和反序列化。
    在这里插入图片描述

  5. 为具体sql语句设置缓存开关(不设置默认允许/打开缓存)
    开启缓存的弊端是数据没有实时性,当数据库中的数据一旦修改,查询的数据还是缓存中的数据没有实时性,对于某些需要实时性显示数据的接口我们可以设置 useCache="false" ,设置该属性后,该接口每次查询出来都是去执行sql查询出实时性数据。如:
    在这里插入图片描述

  6. 为具体sql语句设置缓存刷新开关(不设置默认刷新缓存)
    清空缓存,一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。但是如果你不想刷新缓存只需要这么做:
    Mybatis缓存_第8张图片

测试代码:

@Test
public void test01(){
	TeacherMapper mapper1 = sqlSession.getMapper(TeacherMapper.class);
	//第一次读取,会发行sg1
	Teacher teacher = mapper1.selectone(tno:"1001");
	System.out.println(teacher);
	System.0Ut.println("=============================");
	sqlSession.commit(); // 需要commit后才会把结果放入二级缓存
	
	SqlSession session = sqlSessionFactory.openSession(); // 新开一个session
	TeacherMapper mapper2 = sqlSession.getMapper(TeacherMapper.class);
	//第二此读取数据,不会发行sqL,直接从缓存中获取数据
	Teacher teacher1 = mapper2.selectone(tno:"1001");
	System.out.println(teacher1);
	System.out.println(teacher == teacher1);
}

参考资料:

  1. 哔哩哔哩 逆风两脚兽 Mybatis基础入门
    https://www.bilibili.com/video/BV18D4y117ZJ?share_source=copy_web
  2. 博客园 CodingSh1t MyBatis 二级缓存的开启与配置
    https://www.cnblogs.com/newbee94/p/16264231.html

你可能感兴趣的:(mybatis,缓存,java,一级缓存,二级缓存)