Mybatis缓存
Mybatis和hibernate一样都存在缓存机制,有了缓存查询的速度就提高了,这样就可以提高查询效率。
Myabtis中默认定义了两级缓存:一级缓存、二级缓存
两级缓存
① 一级缓存是mybatis自动开启的,并且我们是没有办法关闭的,但是可以采用手动的方式进行清除(Sqlsession级别)
② 二级缓存就是需要我们自己手动开启(全局),是基于namespace级别的缓存
一级缓存(Local Cache)
mybatis会在会话的Sqlsession对象建立缓存,将每次查询的结果缓存起来,当下次查询的时候,就会去判断有没有跟先前一样的查询,有的话就会直接从缓存中取出结果返回用户,不用再去跟数据库取查询数据。
mybatis在开启一个数据库会话时,会创建一个新的Sqlsession对象,对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象,会话结束时,Sqlsession对象及其内部的Executor、PerpetualCache对象也会一起释放。
Sqlsession调用close()方法,释放一级缓存PerpetualCache对象,一级缓存就不可用。
SqlSession调用clearCache(),就会清空PerpetualCache()对象中的数据,但是对象还是可以使用。
SqlSession中执行CUD,就会清空PerpetualCache()对象的数据,但是对象还是可以使用。
缓存存在的条件:
在同一个Sqlsession中,数据没有改变就不会刷新缓存。
缓存失效的条件:
①并不是同一个Sqlsession对象
②在查询时,查询条件不同
③在查询的期间里进行CUD操作,没有R
④在查询期间手动清除了缓存
session.clearCache();//手动清除缓存
缺点
① 一级缓存不能会话共享,不同的会话对于相同的数据可能有一样的缓存。在多会话或者分布式下,会存在脏数据,要解决这个问题就要使用二级缓存;一级缓存没法关闭。
② session级别缓存,在同一个Sqlsession中,同意的查询不再查询数据库,直接从缓存中取出。
③ statement级别缓存,避免这个问题,可以将一级缓存的级别设置为statement级别,这样在每次查询之后就会清除一级缓存。
二级缓存
在理解一级缓存的理解上,可以知道缓存堆集在Sqlsession类的实例对象上,但是有时候执行方法需要我们自己来写,在service中需要自己来构造方法,那每一次执行完毕之后,Sqlsession实例对象就会关闭,一级缓存就被清空了,这时候缓存是空的拿不到信息,就又要去执行service方法去拿到结果。
二级缓存存储在Mapper实例中,多个Sqlsession对象加载同一个Mapper时,就共享了同一个Mapper缓存。只要哎Mapper和select中配置了缓存,mybatis就会优先从二级缓存中取,再是一级缓存。
Mybatis的查询数据的顺序是:
二级缓存 —> 一级缓存 —> 数据库
当执行CUD的时候,Mapper实例的缓存又会被清空。
二级缓存的作用范围更广,那么他肯定是在Sqlsession的外层,否则不可能被多个Sqlsession共享。
mybatis采用了一个装饰器类来维护——CachingExecutor。如果开启了二级缓存,Mybatis在创建Executor的对象的时候就会对Executor对象进行装饰。CachingExecutor对于查询会去判断有没有缓存结果,有就返回,没有就会委托给真正的查询器Executor实现类。
开启二级缓存的方法
一、配置文件中: mybatis.configuration.cache-enable= true
二、在Mapper.xml中添加**** 标签
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
size="1024"
eviction="LRU"
flushInterval="120000"
readOnly="false"/>
eviction:缓存的回收策略:
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
flushInterval:缓存刷新间隔(任意正整数)
缓存多长时间清空一次,默认不清空,设置一个毫秒值
readOnly:是否只读:
**true:**只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
**false:**非只读:mybatis觉得获取的数据可能会被修改。mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢。
size: 引用数目,缓存对象的大小和运行环境中可用的内存资源,默认1024;
**type="":**指定自定义缓存的全类名:
实现Cache接口即可;
blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。
二级缓存是事务性的,Sqlsession完成并提交时,是完成并回滚。
在Mapper.xml配置中配置了之后select会被缓存,CUD会刷新缓存。
如果cacheEnable = true,但是Maper.xml中没有配置是不会有二级缓存的,但是还会出现CachingExecutor对象。
事务不提交,缓存是不会存在的。
这个原因是由于二级缓存是使用了TransactionalCacheManager来管理,最后调用TransactionalCache的getObject()、putObject()、commit()方法,TransactionalCache里持有真正的Cache对象。在putObject()的时候,只是添加到entriesToAndOnCommit()里面,只有他的commit()方法调用时候才会去执行flushPendingEntries()写入实际缓存。