一级缓存
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
并发工作,二级缓存就是为了解决这个问题。
二级缓存是基于Mapper
(namespace
)级别的缓存,对于同一个Mapper
文件不同sqlSession
对象,可以共享缓存中的内容。
二级缓存默认是不开启的,需要手动开启。
只有当一级缓存,SqlSession
对象使用完毕后能够关闭时,二级缓存才能正常命中,否则将会出现缓存命中为零的现象。
开启二级缓存步骤
-
在
application
配置文件中指定mybatis
的xml
配置文件路径
-
在
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> <!-- 全局参数 --> <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>
-
为具体的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
,也可以指定第三方缓存。
-
使缓存对象的实体类实现序列化接口(
Serializable
)
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,实现序列化接口的目是二级缓存可能会使用硬盘临时存储,所以要实现序列化接口保证对象能够被序列化和反序列化。
-
为具体
sql
语句设置缓存开关(不设置默认允许/打开缓存)
开启缓存的弊端是数据没有实时性,当数据库中的数据一旦修改,查询的数据还是缓存中的数据没有实时性,对于某些需要实时性显示数据的接口我们可以设置useCache="false"
,设置该属性后,该接口每次查询出来都是去执行sql查询出实时性数据。如:
-
为具体
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);
}
参考资料:
- 哔哩哔哩 逆风两脚兽 Mybatis基础入门
https://www.bilibili.com/video/BV18D4y117ZJ?share_source=copy_web
- 博客园 CodingSh1t MyBatis 二级缓存的开启与配置
https://www.cnblogs.com/newbee94/p/16264231.html