Mybatis缓存

一级缓存

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

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

如果在两次查询之间执行了DML操作(Data Manipulation Language),则sqlSession会清空一级缓存,防止脏数据。
在这里插入图片描述

测试代码

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

@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的查询无法共享缓存。

溯源:一级缓存在哪儿?

在这里插入图片描述
其中可以看到默认开启了缓存
在这里插入图片描述

二级缓存

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

二级缓存是基于Mappernamespace)级别的缓存,对于同一个Mapper文件不同sqlSession对象,可以共享缓存中的内容。
在这里插入图片描述

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

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

开启二级缓存步骤

  1. application配置文件中指定mybatisxml 配置文件路径
    在这里插入图片描述

  2. mybatisxml 配置文件路径,设置开启缓存:
    在这里插入图片描述

    <?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>
        	<!-- 使全局的映射器启用或禁用缓存 -->
        	<setting name="cacheEnabled"             value="true"   />
        	<!-- 允许JDBC 支持自动生成主键 -->
        	<setting name="useGeneratedKeys"         value="true"   />
        	<!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
        	<setting name="defaultExecutorType"      value="SIMPLE" />
    		<!-- 指定 MyBatis 所用日志的具体实现 -->
        	<setting name="logImpl"                  value="SLF4J"  />
        	<!-- 使用驼峰命名法转换字段 -->
    		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
    	</settings>	
    </configuration>
    
  3. 为具体的Mapper映射文件的命名空间进行二级缓存的具体配置。
    在这里插入图片描述

    <!-- 配置当前命名空间下mapper的缓存 -->
    <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表示刷新缓存,这样可以避免数据库脏读。但是如果你不想刷新缓存只需要这么做:
    在这里插入图片描述

测试代码:

@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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值