缓存
MyBatis为了提高查询效率和减去数据库的压力,提供了缓存机制,底层使用Map数据结构实现缓存的存储
一级缓存
一级缓存MyBatis默认开启,缓存范围是会话缓存,以下几种情况会导致缓存失效,测试时注意查询结果不能为空,因为空和空是相等的
- 同一个会话中获取相同数据时,第二次会从缓存中拿
sqlSession = sessionFactory.openSession(); //获取会话
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student1 = studentMapper.selectById(1);
Student student2 = studentMapper.selectById(1);
System.out.println(student1 == student2); //true,命中缓存
- 不同SqlSession对象无法公用缓存
SqlSession sqlSession1 = sessionFactory.openSession(); //第一个会话
StudentMapper studentMapper1 = sqlSession1.getMapper(StudentMapper.class);
Student student1 = studentMapper1.selectById(1);
SqlSession sqlSession2 = sessionFactory.openSession(); //第二个会话
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
Student student2 = studentMapper2.selectById(1);
System.out.println(student1 == student2); //false,不同和会话不共享缓存
- 写操作commit时会清空缓存,保证读取数据一致,或手动清空缓存
sqlSession = sessionFactory.openSession(); //获取会话
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student1 = studentMapper.selectById(1);
sqlSession.commit(); //提交
//sqlSession.clearCache(); //手动清空缓存
Student student2 = studentMapper.selectById(1);
System.out.println(student1 == student2); //false,提交或手动清空缓存,都会使得缓存失效,保证数据一致性
二级缓存
二级缓存需要手动开启,缓存范围是Namespace缓存,只有当前session关闭时,才会将一级缓存中的内容写入二级缓存中
二级缓存配置参数
全局缓存配置参数
- 使用
size
属性是缓存对象个数,默认1024个,一个集合也算一个对象 - 使用
eviction
是缓存的清除策略,当缓存对象数量达到上限后,自动清除的策略,有以下几种可选值- LRU:最近最少未使用(默认)
- FIFO:先进先出
- SOFT:软引用,移除基于垃圾回收器状态和软引用规则对象
- WEAK:弱引用,更积极的移除,基于垃圾回收器状态和弱引用规则对象
- 使用
flushInterval
属性决定自动刷新缓存时间间隔,单位毫秒,默认不刷新 - 使用
readOnly
属性决定读取缓存对象策略,在注解中使用的是readWrite
属性,并且与下面配置相反- 为
false
时(默认),则会读取中对象的副本,是通过序列化,所以需要为对象实现序列化标志接口Serializable
- 为
true
时,则直接从缓存中读取对象本身
- 为
单个SQL缓存配置参数
- 对某个SQL配置
useCache=false
可对某个SQL单独关闭缓存机制,因为一个集合也算一个对象,所以通常不会将一个返回多条记录的SQL进行缓存 - 对某个SQL配置
flushCache=true
可在执行完该SQL后,一并将缓存清空,有时希望在执行数据更新操作时未提交数据,但又希望刷新缓存
xml方式
在该映射xml文件中增加下面配置即可为当前命名空间开启缓存
<!--<cache-ref namespace="course"/>-->
<!-- cache-ref 标签可指定使用别的命名空间中定义的缓存设置-->
<cache size="1024" eviction="LRU" flushInterval="600000" readOnly="true"/>
<select id="selectById" parameterType="Integer" resultType="com.Student" useCache="false" flushCache="true">
<!--测试时将单个SQL缓存配置 useCache="false" 和 flushCache="true" 两个配置项删除-->
select * from students where stu_id = #{value}
</select>
下面是用于测试的关键代码,测试时注意查询结果不能为空,因为空和空是相等的
SqlSession sqlSession1 = sessionFactory.openSession(); //第一个会话
Student student1 = sqlSession1.selectOne("student.selectById", 1);
sqlSession1.close(); //只有关闭或提交后,session才会被写入二级缓存中
SqlSession sqlSession2 = sessionFactory.openSession(); //第二个会话
Student student2 = sqlSession2.selectOne("student.selectById", 1);
System.out.println(student1 == student2); //true,当readOnly为false时会返回false,因为是对象副本
注解方式
package com;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.cache.decorators.LruCache;
//@CacheNamespaceRef(CourseMapper.class) //CacheNamespaceRef注解可指定使用别的Mapper中定义的缓存设置
@CacheNamespace(size = 1024, eviction = LruCache.class, flushInterval = 600000, readWrite = false)
public interface StudentMapper {
@Select("select * from students where stu_id = #{id}")
//@Options(useCache = false, flushCache = Options.FlushCachePolicy.TRUE) //单个SQL配置缓存使用Options注解
Student selectById(Integer id);
}
下面是用于测试的关键代码,测试时注意查询结果不能为空,因为空和空是相等的
SqlSession sqlSession1 = sessionFactory.openSession(); //第一个会话
StudentMapper studentMapper1 = sqlSession1.getMapper(StudentMapper.class);
Student student1 = studentMapper1.selectById(1);
sqlSession1.close(); //只有关闭或提交后,session才会被写入二级缓存中
SqlSession sqlSession2 = sessionFactory.openSession(); //第二个会话
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
Student student2 = studentMapper2.selectById(1);
System.out.println(student1 == student2); //true,当readWrite为true时会返回false,因为是对象副本
第三方缓存
由于MyBatis实现的缓存过于简陋,就是一个Map数据结构进行存储,所以MyBatis留出一个org.apache.ibatis.cache.Cache
接口,实现该接口中定义的缓存对象的方法即可自定义二级缓存的存储,在使用cache
标签配置时使用type
属性指定缓存实现类的全类名即可,就像这样<cache type="com.Cache"/>
,一般直接使用第三方写好的缓存
可查询MyBatis官方GIthub,该项目下的所有整合包,比如redis-cache
、ehcache-cache
等,具体使用方式可参考这些适配器包的官方文档,点击进入适配器包后点击查看文档界面可能会出错(2020-12)因为文档跳转页面是以mybatis.github.io
为域名的,改为mybatis.org
域名即可
Comments NOTHING