MyBatis之缓存(一级缓存、二级缓存)

来源:互联网 发布:战地4 FY-js 狙击枪 编辑:程序博客网 时间:2024/05/01 17:34

1,        MyBatis的解析

MyBatis的解析工作由XmlConfiguraBuilder类来实现的,它将MyBatis的所有配置信息解析到Configuration中,为之后的使用提供支持。

2,        MyBatis的一级缓存

MyBatis的一级缓存是SqlSession级别的缓存,每个SqlSession都有一个以及缓存。

我们在对数据库进行操作时,会创建一个SqlSession,而具体的操作都交给了Executor执行器来实现的,SqlSession只是MyBatis对外提供的接口,Executor内部维护了一个Cache对象,是实现类PerpectualCache实例,Cache对象保存了query查询的cacheKey和查询结果的映射。cacheKey是由statementId、rowbounds、原始sql语句以及参数生成。

当我们执行查询时,首先通过构造cacheKey,去Cache中查询是否缓存了结果,有则直接返回,没有再去数据库中差,然后将结果保存到Cache中再返回。

一级缓存实际上是使用PerpetualCache来维护的,其内部是通过一个HashMap来实现的

3,        MyBatis的二级缓存

MyBatis的二级缓存是Application级别的缓存,但是MyBatis对其进行了细化,细化为Mapper级别的缓存,每个Mapper有一个Cache,多个Mapper可以通过cache-ref公用一个Cache。使用MyBatis的二级缓存有三种选择:

1,        MyBatis自身提供的缓存实现

2,        用户自定义的Cache接口实现

3,        跟第三方内存缓存库的集成,比如Encache!

开启二级缓存需要三步:

1,        MyBatis全局配置文件中将cacheEnable设置为true;

2,        Mapper文件中设置cache

3,        具体的select的statement配置中设置useCache为true

MyBatis的二级缓存其实是通过对Executor来实现的。使用二级缓存时,SqlSession创建Executor对象时,会为Executor对象加上一个装饰者:CachingExecutor,其实就是创建一个CachingExecutor对象,它是Executor的装饰者,设计模式之装饰模式自己下去看!当进行查询时,首先CachingExecutor先在二级缓存中查找,找到则直接返回,没有找到再让真正的Executor去执行它的操作(一级缓存和数据库查询),最后CachingExecutor会把Executor的返回结果放到缓存中,然后再返回。

对于MyBatis自身提供的缓存实现,MyBatis定义了大量的Cache的装饰器来增强Cache缓存的功能,对于每个Cache而言,都提供了容量限制,通常采用LRU、FIFO、Scheduled来对缓存进行清除。

4,        MyBatis的二级缓存带来的问题

MyBatis的二级缓存是松散的Cache缓存管理和维护,一个Cache对象只能关联到自身Mapper的操作,Mapper之间的缓存关系比较松散,这样会导致一个问题:

       A表、B表,A表的查询关联了B表,这条查询结果放到了MapperA的Cache中,B表的update会清除MapperB的Cache,但是MapperA的Cache缓存了B的这些数据,导致B的更新对MapperA不可见,导致数据错误。

       解决:

1,        A表和B表共用一个Cache,这样可以解决,但是这样会导致缓存的使用效率低,因为两个Mapper的更新操作都会清空Cache,频繁地清空Mapper导致命中率和使用率都变得很低!

2,        某些表执行更新操作后,去清空跟这些表有关联的查询语句造成的缓存。决定清空哪些查询缓存,是在EnhancedCachingManager中维护的:update类型的statementId和select类型的statementId集合的映射!

针对2的解决,可以使用Enhanced-Cache(加强的缓存)插件,Enhanced-Cache插件由两个构建组成:EnhancedCachingExecutor、EnhancedCachingManager。

EnhancedCachingExecutor,其实就是一个针对Executor的拦截器,拦截Executor的query和update操作,

1,        当Executor执行query操作时

1.1   记录下该查询的statementId和CacheKey,将其添加到EnhancedCachingManager中

1.2   记录下该查询的statementId和此statementId所属的Mapper内的Cache缓存对象的引用

2,        当Executor执行update操作时,将update操作的statementId传递给EnhancedCachingManager,让它根据statementId的配置,去清空指定的查询语句所产生的缓存。

EnhancedCachingManager,它维护着一下几样东西:

1,        整个MyBatis的所有查询所产生的CacheKey集合

2,        所有statementId及其对应的Cache缓存对象的引用

3,        update类型的statementId和select类型的statementId集合的映射,用于当执行update操作时,根据此映射决定清空的查询缓存。

0 0
原创粉丝点击