欢迎您的访问
专注于Java技术系列文章的Java技术分享网站
精选技术专栏

MyBatis 工作笔记 (四):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。

二、开启二级缓存示例

1、在核心配置文件SqlMapConfig.xml中加入以下内容(开启二级缓存总开关)

 <settings>
   <setting name="cacheEnabled" value="true"/>
 </settings>

2、在映射文件中,加入以下内容,开启二级缓存

 <mapper namespace="me.gacl.mapping.userMapper">
 <!-- 开启二级缓存 -->
 <cache/>

字面上看就是这样。这个简单语句的效果如下:

  • 映射语句文件中的所有 select 语句将会被缓存。
  • 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
  • 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
  • 根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
  • 缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
  • 缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

    所有的这些属性都可以通过缓存元素的属性来修改。比如:

 <cache
   eviction="FIFO"
   flushInterval="60000"
   size="512"
   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使用二级缓存。

 <select id="findUserByName" parameterType="java.lang.String" resultType="com.study.mybatis.model.UserModel" userCache="false" >
     select * from t_user where username LIKE '%${value}%'
 </select>

刷新二级缓存:

 <select id="findUserByName" parameterType="java.lang.String" resultType="com.study.mybatis.model.UserModel" flushCache="true" >
     select * from t_user where username LIKE '%${value}%'
 </select>

三、使用自定义缓存

除了这些自定义缓存的方式,你也可以通过实现你自己的缓存或为其他第三方缓存方案 创建适配器来完全覆盖缓存行为。

 <cache type="com.domain.something.MyCustomCache"/>

这个示 例展示了如何使用 一个 自定义的缓存实 现。type 属性指定的类必须实现org.mybatis.cache.Cache 接口。这个接口是MyBatis 框架中很多复杂的接口之一,但是简单给定它做什么就行。

 public interface Cache {
   String getId();
   int getSize();
   void putObject(Object key, Object value);
   Object getObject(Object key);
   boolean hasKey(Object key);
   Object removeObject(Object key);
   void clear();
   ReadWriteLock getReadWriteLock();
 }

缓存配置和缓存实例是绑定在 SQL 映射文件的命名空间的。因此,所有在相同命名空间的语句正如绑定的缓存一样。 语句可以修改和缓存交互的方式,或在语句的基础上使用两种简单的属性来完全排除它们。默认情况下,语句可以这样来配置:

 <select ... flushCache="false" useCache="true"/>
 <insert ... flushCache="true"/>
 <update ... flushCache="true"/>
 <delete ... flushCache="true"/>

因为那些是默认的,你明显不能明确地以这种方式来配置一条语句。相反,如果你想改变默认的行为,只能设置flushCache和useCache属性。比如,在一些情况下你也许想排除从缓存中查询特定语句结果,或者你也许想要一个查询语句来刷新缓存。相似地,你也许有一些更新语句依靠执行而不需要刷新缓存。

来源:https://www.cnblogs.com/leeSmall/category/1093234.html

文章永久链接:https://tech.souyunku.com/?p=14434

赞(97) 打赏



版权归原创作者所有,任何形式转载请联系作者;搜云库技术团队 » MyBatis 工作笔记 (四):Mybatis缓存

评论 抢沙发

一个专注于Java技术系列文章的技术分享网站

觉得文章有用就打赏一下文章作者

微信扫一扫打赏

微信扫一扫打赏