MyBatis(6),缓存
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。
如果没有缓存,那么每次查询的时候都需要从数据库中加载数据,这会造成IO的性能问题,所以,在很多情况下如果连续执行两条相同的sql语句,可以直接从缓存中获取,如果获取不到,那么再去查询数据库,这意味着查询完成的结果需要放到缓存中.
MyBatis默认情况下,只启用了本地的会话缓存(一级缓存),它仅仅对一个会话中的数据进行缓存。
缓存分类
- 一级缓存:表示sqlSession级别的缓存,每次查询的时候会开启一个会话,此会话相当于一次连接,关闭之后自动失效
- 二级缓存:全局范围内的缓存,sqlSession关闭之后才会生效
- 第三方缓存:集成第三方的组件,来充当缓存的作用
一级缓存
表示将数据存储在sqlSession中,关闭之后自动失效,默认情况下是开启的
在同一个会话之内,如果执行了多个相同的sql语句,那么除了第一个之外,所有的数据都是从缓存中进行查询的
在某些情况下,一级缓存可能会失效
1.在同一个方法中,可能会开启多个会话,此时需要注意,会话跟方法没有关系,不是一个方法就只能有一个会话,所以严格记住,缓存的数据是保持在sqlSession中的
2.当传递对象的时候,如果对象中的属性值不同,也不会走缓存
3.当在一个会话中,如果修改了数据,那么缓存会失效(没有提交也是会失效的),不同会话是相互不受影响的
注意:当一个方法中有其它的会话的时候,其它会话修改数据不会影响当前会话的缓存
4.如果在一个会话过程中,手动清空了缓存,那么缓存也会失效
二级缓存
表示的是全局缓存,必须要等到sqlSession关闭之后才会生效
默认是关闭的,如果需要开启的话,需要进行如下设置
1.修改全局配置文件,在settings中添加配置
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
2.指定在哪个映射文件中使用缓存的配置
<?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.yangqihang.dao.EmpDao">
<select>...</select>
<cache></cache>
</mapper>
3.对应的Java实体类必须要实现序列化的接口
public class Emp implements Serializable{
//省略
}
在使用二级缓存的时候,可以包含多个属性值:
<!--
eviction:缓存淘汰机制
LRU:最近最少使用
FIFO:先进先出,按照添加缓存的顺序执行
SOFT:软引用,基于垃圾回收器状态和软引用规则移除对象.
WEAK:弱引用,更积极地基于垃圾收集器状态和弱引用规则移除对象.
flushInterval:设置多长时间进行缓存刷新
size:引用的条数,是一个正整数,缓存中可以存储多少个对象,一般不设置,如果设置的话不要太大,会导致内存溢出
readOnly:只读属性
true:只读缓存,会给所有的调用的方法返回该对象的实例,不安全
false:读写缓存,只是返回缓存对象的拷贝,比较安全
-->
<cache eviction="LRU" size="512" flushInterval="60000" readOnly="true"></cache>
问题
一级缓存和二级缓存有没有可能同时存在?
不会同时存在,因为二级缓存生效的时候是在sqlSession关闭的时候
当查询数据的时候,我们是先查询一级缓存还是先查询二级缓存?
先查询二级缓存,然后再查询一级缓存
第三方缓存
以ehcache为例
导入pom依赖
<!-- 第三方缓存ehcache -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.0</version>
</dependency>
导入ehcache配置
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\ehcache" />
<defaultCache
maxElementsInMemory="1"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
<!--
属性说明:
diskStore:指定数据在磁盘中的存储位置。
defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
maxElementsInMemory - 在内存中缓存的element的最大数目
maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
-->
</ehcache>
类似开启二级缓存的步骤
setting设置和在指定映射文件中开启缓存配置,需要设置type属性
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
这样第三方缓存就好了,每次查询会在diskStore 指定的路径下生成文件