Mybatis缓存

来源:互联网 发布:平民护肤品推荐 知乎 编辑:程序博客网 时间:2024/04/29 23:08

缓存概述 

  • 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持;
  • 一级缓存基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
  • 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache、Hazelcast等。
  • 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
  • MyBatis 的缓存采用了delegate机制 及 装饰器模式设计,当put、get、remove时,其中会经过多层 delegate cache 处理,其Cache类别有:BaseCache(基础缓存)、EvictionCache(排除算法缓存) 、DecoratorCache(装饰器缓存):          BaseCache         :为缓存数据最终存储的处理类,默认为 PerpetualCache,基于Map存储;可自定义存储处理,如基于EhCache、Memcached等; 
              EvictionCache    :当缓存数量达到一定大小后,将通过算法对缓存数据进行清除。默认采用 Lru 算法(LruCache),提供有 fifo 算法(FifoCache)等; 
              DecoratorCache:缓存put/get处理前后的装饰器,如使用 LoggingCache 输出缓存命中日志信息、使用 SerializedCache 对 Cache的数据 put或get 进行序列化及反序列化处理、当设置flushInterval(默认1/h)后,则使用 ScheduledCache 对缓存数据进行定时刷新等。
  • 一般缓存框架的数据结构基本上都是 Key-Value 方式存储,MyBatis 对于其 Key 的生成采取规则为:[hashcode : checksum : mappedStementId : offset : limit : executeSql : queryParams]。
  • 对于并发 Read/Write 时缓存数据的同步问题,MyBatis 默认基于 JDK/concurrent中的ReadWriteLock,使用ReentrantReadWriteLock 的实现,从而通过 Lock 机制防止在并发 Write Cache 过程中线程安全问题


一级缓存与二级缓存

MyBatis将数据缓存设计成两级结构,分为一级缓存、二级缓存:
一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改);
二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Application应用。

MyBatis中一级缓存和二级缓存的组织如下图所示:



一级缓存的工作机制:
一级缓存是Session会话级别的,一般而言,一个SqlSession对象会使用一个Executor对象来完成会话操作,Executor对象会维护一个Cache缓存,以提高查询性能。
二级缓存的工作机制:
如上所言,一个SqlSession对象会使用一个Executor对象来完成会话操作,MyBatis的二级缓存机制的关键就是对这个Executor对象做文章。如果用户配置了"cacheEnabled=true",那么MyBatis在为SqlSession对象创建Executor对象时,会对Executor对象加上一个装饰者:CachingExecutor,这时SqlSession使用CachingExecutor对象来完成操作请求。CachingExecutor对于查询请求,会先判断该查询请求在Application级别的二级缓存中是否有缓存结果,如果有查询结果,则直接返回缓存结果;如果缓存中没有,再交给真正的Executor对象来完成查询操作,之后CachingExecutor会将真正Executor返回的查询结果放置到缓存中,然后在返回给用户。
MyBatis的二级缓存设计得比较灵活,你可以使用MyBatis自己定义的二级缓存实现;你也可以通过实现org.apache.ibatis.cache.Cache接口自定义缓存;也可以使用第三方内存缓存库,如Memcached等。



一级缓存默认开启,它的实现为PerpetualCache,作用范围为Session,对于同一个Session,如果查询同一个事物查询两次,那么只执行一次数据库操作。它的清空条件有如下三种:

* 写操作

* 手动执行SqlSession#clearCache()

* SqlSession#close()关闭之后缓存当然要清空,所以数据库连接池不会发生Session之间共享一级缓存的情况。


二级缓存默认关闭,需要手动开启。它的作用域为mapper,是多线程之间共享的缓存,是应用级缓存,多个Session可以共用同一个mapper的缓存,每一个mapper维护一份缓存对象,但是可以配置多个mapper共用一份缓存对象,通过cache-ref标签。


在SELECT语句中配置刷新缓存,如下:
<select id="aaa" parameterType="string" resultType="integer"  flushCache="true"> 
 
 
在mybatis3.1之后,可以配置本地缓存的作用域。在mybatis.xml中配置,如下:
<setting name="localCacheScope" value="SESSION"/>           作用域为SESSION,这位默认值。
<setting name="localCacheScope" value=" STATEMENT "/>    作用域为STATEMENT,即作用域为SQL。
 
 
二级缓存(second level cache),作用域默认为Mapper(Namespace)。
二级缓存可以被配置为打开或者关闭,默认为关闭,在mybatis.xml中配置。
<setting name="cacheEnabled" value="true"/>
当全局的二级缓存(setting中配置)设置为关闭时可以在Mapper XML中配置单个mapper的二级缓存为打开,配置如下:
<cache />
 
当全局的二级缓存(setting中配置)设置为打开时,mapper中这个配置无效,即mapper中配置为关闭该mapper的二级缓存也是打开。
如果想对某条SQL单独对待,可以在SELECE语句中配置useCache,配置如下:
<select id="aaa" parameterType="string" resultType="integer" useCache="false"> 

在mybatis框架中,在sqlSession未关闭之前,在一个session里面,如果执行相同的select语句,mybatis不会重新查询数据库,而是直接返回缓存在内存中的查询结果,这个是与myBatis的cache配置无关的,更改配置文件不起作用,要调用sqlSession.clearcache()函数才可以


在MyBatis中有flushCache、useCache这两个配置属性,分为下面几种情况:
(1)当为select语句时:
flushCache默认为false,表示任何时候语句被调用,都不会去清空本地缓存和二级缓存。
useCache默认为true,表示会将本条语句的结果进行二级缓存。
(2)当为insert、update、delete语句时:
flushCache默认为true,表示任何时候语句被调用,都会导致本地缓存和二级缓存被清空。
useCache属性在该情况下没有。
上面的信息我是从MyBatis官方文档中找到的,会发现当为select语句的时候,如果没有去配置flushCache、useCache,那么默认是启用缓存的,所以,如果有必要,那么就需要人工修改配置,修改结果类似下面:


0 0
原创粉丝点击