Mybatis缓存
Posted 小不点啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis缓存相关的知识,希望对你有一定的参考价值。
一、MyBatis缓存介绍
MyBatis 提供了一级缓存和二级缓存的支持
1. 一级缓存: 默认开启,基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。在同一个SqlSession中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则SqlSession的缓存清空。
注意:
每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。
SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。
2. 二级缓存:需要手动开启,与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。在同一个namespace下的mapper文件中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则二级缓存清空。
注意:
二级缓存是mapper级别的。Mybatis默认是没有开启二级缓存。
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存。
3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D(增删改) 操作后,默认该作用域下所有 select 中的缓存将被clear。
二、开启二级缓存示例,在sql樱色xml文件xxMapper.xml文件中添加如下配置
1、 在核心配置文件SqlMapConfig.xml中加入以下内容(开启二级缓存总开关)
1 <settings> 2 <setting name="cacheEnabled" value="true"/> 3 </settings>
2、在映射文件中,加入以下内容,开启二级缓存
1 <mapper namespace="me.gacl.mapping.userMapper"> 2 <!-- 开启二级缓存 --> 3 <cache/>
字面上看就是这样。这个简单语句的效果如下:
- 映射语句文件中的所有 select 语句将会被缓存。
- 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
- 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
- 根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
- 缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
- 缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
所有的这些属性都可以通过缓存元素的属性来修改。比如:
1 <cache 2 eviction="FIFO" 3 flushInterval="60000" 4 size="512" 5 readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。
可用的收回策略有:
- LRU – 最近最少使用的:移除最长时间不被使用的对象。
- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
- SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
- WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
3、实现序列化
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象(实体类)执行序列化。
如果该类存在父类,那么父类也要实现序列化。
4、禁用二级缓存和刷新二级缓存
禁用二级缓存:该statement中设置userCache=false可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存。
1 <select id="findUserByName" parameterType="java.lang.String" resultType="com.study.mybatis.model.UserModel" userCache="false" > 2 select * from t_user where username LIKE ‘%${value}%‘ 3 </select>
刷新二级缓存:
1 <select id="findUserByName" parameterType="java.lang.String" resultType="com.study.mybatis.model.UserModel" flushCache="true" > 2 select * from t_user where username LIKE ‘%${value}%‘ 3 </select>
三、使用自定义缓存
除了这些自定义缓存的方式,你也可以通过实现你自己的缓存或为其他第三方缓存方案 创建适配器来完全覆盖缓存行为。
1 <cache type="com.domain.something.MyCustomCache"/>
这个示 例展示了如何使用 一个 自定义的缓存实 现。type 属性指定的类必须实现org.mybatis.cache.Cache 接口。这个接口是MyBatis 框架中很多复杂的接口之一,但是简单 给定它做什么就行。
1 public interface Cache { 2 String getId(); 3 int getSize(); 4 void putObject(Object key, Object value); 5 Object getObject(Object key); 6 boolean hasKey(Object key); 7 Object removeObject(Object key); 8 void clear(); 9 ReadWriteLock getReadWriteLock(); 10 }
缓存配置和缓存实例是绑定在 SQL 映射文件的命名空间的。因此,所有在相同命名空间的语句正如绑定的缓存一样。 语句可以修改和缓存交互的方式,或在语句的基础上使用两种简单的属性来完全排除它们。默认情况下,语句可以这样来配置:
1 <select ... flushCache="false" useCache="true"/> 2 <insert ... flushCache="true"/> 3 <update ... flushCache="true"/> 4 <delete ... flushCache="true"/>
因为那些是默认的,你明显不能明确地以这种方式来配置一条语句。相反,如果你想改 变默认的行为,只能设置flushCache和useCache属性。比如,在一些情况下你也许想排除从缓存中查询特定语句结果,或者你也许想要一个查询语句来刷新缓存。相似地,你也许有一些更新语句依靠执行而不需要刷新缓存。
以上是关于Mybatis缓存的主要内容,如果未能解决你的问题,请参考以下文章