mybatis学习记录5mybatis的二级缓存

abcwt112的博客园      2022-04-15     690

关键词:

 

主题

  之前学习了一下MyBatis的一级缓存,主要涉及到BaseExecutor这个类. 现在准备学习记录下MyBatis二级缓存.

 

配置二级缓存与初始化发生的事情

首先二级缓存默认是不开启的,需要自己配置开启.

如上图,需要在configuration里去开启.

其次在需要用到二级缓存的Mapper的配置里做一些操作,如下图,增加一个cache节点

至此就可以在UserMapper上开启二级缓存了.

 

当MaBatis初始化的时候,需要解析各种XML配置来生成SQLSessionFactory,解析Mapper的配置也是其中一环.而解析Mapper的配置中,解析Cache节点又是其中的一部分.

 

这个解析cache会做什么事情呢?

如上图所示,会往builderAssistant里去新建一个Cache对象(其中的参数是你之前XML里配置的).

Cache类的设计也是装饰着模式,层层嵌套.比如我们new出来的Cache中会包裹一个打印缓存命中信息的LoggingCache,我们指定的LruCache包裹着PerpetualCache(一级缓存也使用这个Cache)等等.

 

MapperBuilderAssistant是个Builder模式,解析Mapper的最后会调用assistant的addMappedStatement方法.

 1     public MappedStatement addMappedStatement(
 2             String id,
 3             SqlSource sqlSource,
 4             StatementType statementType,
 5             SqlCommandType sqlCommandType,
 6             Integer fetchSize,
 7             Integer timeout,
 8             String parameterMap,
 9             Class<?> parameterType,
10             String resultMap,
11             Class<?> resultType,
12             ResultSetType resultSetType,
13             boolean flushCache,
14             boolean useCache,
15             boolean resultOrdered,
16             KeyGenerator keyGenerator,
17             String keyProperty,
18             String keyColumn,
19             String databaseId,
20             LanguageDriver lang,
21             String resultSets) {
22 
23         if (unresolvedCacheRef) {
24             throw new IncompleteElementException("Cache-ref not yet resolved");
25         }
26 
27         id = applyCurrentNamespace(id, false);
28         boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
29 
30         MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
31                 .resource(resource)
32                 .fetchSize(fetchSize)
33                 .timeout(timeout)
34                 .statementType(statementType)
35                 .keyGenerator(keyGenerator)
36                 .keyProperty(keyProperty)
37                 .keyColumn(keyColumn)
38                 .databaseId(databaseId)
39                 .lang(lang)
40                 .resultOrdered(resultOrdered)
41                 .resultSets(resultSets)
42                 .resultMaps(getStatementResultMaps(resultMap, resultType, id))
43                 .resultSetType(resultSetType)
44                 .flushCacheRequired(valueOrDefault(flushCache, !isSelect))
45                 .useCache(valueOrDefault(useCache, isSelect))
46                 .cache(currentCache);
47 
48         ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
49         if (statementParameterMap != null) {
50             statementBuilder.parameterMap(statementParameterMap);
51         }
52 
53         MappedStatement statement = statementBuilder.build();
54         configuration.addMappedStatement(statement);
55         return statement;
56     }
View Code

把刚才new出来的cache设置到MappedStatement.Builder中,最后build出一个MappedStatement,并添加到Configuration里. 如下图

 

所以其实我们刚才在Mapper的XML里配置的cache,最后生成对应的java Cache对象,是放在MappedStatement里的,而MappedStatement是什么东西? 看了如下3个截图大家应该就明白了.就是你Mapper XML里配置的一个一个DML对应的节点,当然1个Mapper.XML里会有很多这样的节点,而他们是公用1个Cache的.

MappedStatement是全局唯一的对象,被放到了Configuration里,不同的Executor需要用到的时候都会从Configuration里去找SQL对应的MappedStatement.(其实是SqlSession调用Executor的query方法的时候会去根据类.方法名在configuration里查找mappedStatement并传入)

 

 

 

 

CachingExecutor

正如之前文章记录的那样,CachingExecutor是包裹在BaseExecutor外的一层Executor,使用的是装饰着模式. 二级缓存主要是在它里面实现的.

先来看一个Demo

2018-10-14 12:04:17,138 DEBUG [main] logging.LogFactory : Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Cache Hit Ratio [test.mapper.UserMapper]: 0.0
Opening JDBC Connection
Sun Oct 14 12:04:17 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Created connection 25300561.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1820e51]
==>  Preparing: select id, user_id, user_name, real_name, email, creator_uid, modifier_uid, created_at, updated_at, del from user where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, user_id, user_name, real_name, email, creator_uid, modifier_uid, created_at, updated_at, del
<==        Row: 1, 1, test, realName, jyzjyz12@163.com, 1, 1, 2018-09-24 10:10:43.0, 2018-09-24 10:10:46.0, 0
<==      Total: 1
User{id=1, userId=1, userName='test', realName='realName', email='jyzjyz12@163.com', creatorUid=1, modifierUid=1, createdAt=Mon Sep 24 10:10:43 CST 2018, updatedAt=Mon Sep 24 10:10:46 CST 2018, del=false}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1820e51]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1820e51]
Returned connection 25300561 to pool.
Cache Hit Ratio [test.mapper.UserMapper]: 0.5
User{id=1, userId=1, userName='test', realName='realName', email='jyzjyz12@163.com', creatorUid=1, modifierUid=1, createdAt=Mon Sep 24 10:10:43 CST 2018, updatedAt=Mon Sep 24 10:10:46 CST 2018, del=false}

如上图,从1个SQLSessionFactory里获取了2个SqlSession,分别调用了1次selectByPrimaryKey.

而红色部分输出看到 第一个sqlSession打印了1次SQL, 第二次调用selectByPrimaryKey的时候会打印蓝色的部分,输出缓存命中,概率为1/2,然后没有打印红色的查询语句,而是直接输出返回打印了之前缓存中的对象.

 

CachingExecutor的query方法如下图

与BaseExecutor的处理方法大致类似,只是先会从MapperedStatement里去寻找是否配置过缓存,有的话就从TransactionalCacheManager中通过Cache做为Key去找TransactionalCache,再从TransactionalCache中根据CacheKey查找结果, TransactionalCache也是Cache的一种实现,目的是为了支持事务回滚提交操作.

TransactionalCache中缓存对象的key为CacheKey,CacheKey之前在一级缓存中已经分享过,value为数据库查询结果,即一个ArrayList.

如果缓存中没有,那就委托内部wrapped的对象,也就是SImpleExecutor去调用query去数据库中找.

 

小结

总结一下二级缓存如何实现:

1.初始化阶段初始化Cache设置到MappedStatement里,MappedStatement设置到Configuration里.

2.执行查询的时候SqlSession去Configuration里找到MappedStatement传给CachingExecutor.

3.CachingExecutor获取MappedStatement再获取其中的Cache,根据Cache是否null,判断是否有开启二级缓存.

4.如果有开启,那Cache不为null,去TransactionalCacheManager中根据Cache为Key找到TransactionalCache,为null就委托SImpleExecutor继续查数据库.不为null,就在TransactionalCache根据CacheKey找到对应的Value并返回.

 

23mybatis学习——mybatis的二级缓存

MyBatis一级缓存最大的共享范围就是一个SqlSession内部,那么如果多个SqlSession需要共享缓存,则需要开启二级缓存,开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查... 查看详情

mybatis学习13mybatis中的二级缓存

1.二级缓存的原理  前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的。为了更加清楚的描述二级缓存,先来看一个示意图... 查看详情

mybatis学习--缓存(一级和二级缓存)

声明:学习摘要!MyBatis缓存  我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些... 查看详情

mybatis学习笔记:一级缓存二级缓存(代码片段)

文章目录13.1、简介13.2、MyBatis缓存13.3、一级缓存测试查看一级缓存缓存失效的情况13.4、二级缓存13.1、简介1.什么是缓存(cache)?存在内存中的临时数据将用户经常查询的数据放在缓存(内存)中,用户... 查看详情

转mybatis学习总结——mybatis缓存

【转】MyBatis学习总结(七)——Mybatis缓存一、MyBatis缓存介绍  正如大多数持久层框架一样,MyBatis同样提供了一级缓存和二级缓存的支持一级缓存:基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Sessionflush或close... 查看详情

mybatis学习动态加载一二级缓存

一、动态加载:resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。需求:如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当需要查询... 查看详情

mybaties的缓存(转)

内容大纲.png前言本篇意在通过Hibernate和Mybaitis缓存,通过对比学习,同时弄懂这两者中的区别Hibernate中的缓存Hibernate中一般常用的缓存有三个,一级缓存,二级缓存,查询缓存,要了解一二级缓存的可以点击->图解SSH-Hibernate,这里主要... 查看详情

mybatis缓存--------系统缓存及简单配置介绍

前言Mybatis的缓存主要有两种:系统缓存,也就是我们一级缓存与二级缓存;自定义的缓存,比如Redis、Enhance等,需要额外的单独配置与实现,具体日后主要学习介绍。在这里主要记录系统缓存的一些简单概念,并没有涉及原理... 查看详情

mybatis的二级缓存

文章目录MyBatis的二级缓存MyBatis默认是开启一级缓存的开启MyBatis的二级缓存为什么要开启二级缓存在mybatis的配置文件中进行配置在对应的mapper映射文件中声明相关的DO对象需要实现序列化测试动态代理接口执行更新方法后会清空... 查看详情

mybatis学习整合第三方缓存ehcache(代码片段)

第三方缓存只能代替Mybatis的二级缓存文章目录一、添加依赖二、各jar包功能三、创建EHCache的配置文件ehcache.xml四、设置二级缓存的类型五、加入logback日志六、EHCache配置文件说明七、示例一、添加依赖<!--MybatisEHCache整合包-->... 查看详情

mybatis系统性详解(学习笔记)(代码片段)

目录mybatis知识传统JDBC不足mybatis基础mybatis核心应用配置与原理解析mybatis核心概念整体认识mybatis源码包mybatis基本流程类调用mybatis流程记录mybatis处理流程图mybatis*之sessionmybatis之mappermybatis之sqlmybatis之executormybatis之Cache一级缓存二... 查看详情

mybatis学习12mybatis中的一级缓存

缓存的作用是减轻数据库的压力,提高数据库的性能的。mybatis中提供了一级缓存和二级缓存,先来看一下两个缓存的示意图:    从图中可以看出: 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession... 查看详情

使用redis做mybaties的二级缓存-mybatis二级缓存小心使用

 Mybatis默认对二级缓存是关闭的,一级缓存默认开启;下面就说说为什么使用二级缓存需要注意:    二级缓存是建立在同一个namespace下的,如果对表的操作查询可能有多个namespace,那么得到的数据就是错误的... 查看详情

mybatis的缓存

1.缓存是什么   在Mybatis里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录,从而提高查询的效率。  Mybatis的缓存分为一级缓存和二级缓... 查看详情

《深入理解mybatis原理7》mybatis的二级缓存的设计原理

《深入理解mybatis原理》MyBatis的二级缓存的设计原理MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。本文将全面分析MyBatis的二级缓存的设计原理。1.MyBatis的缓存机制整体设计以及二... 查看详情

mybatis缓存

mybatis的延迟加载和缓存技术开始 mybatis一级缓存  mybatis的二级缓存mybatis默认是没有开启二级缓存的。 开启二级缓存需要在mybatis的全局配置文件sqlMapConfig.xml中加入 除了开启二级缓存开关外,还需要在各自的map... 查看详情

mybatis——一级缓存二级缓存

一、Mybatis缓存●MyBatis包含一个非常强大的查询緩存特性,它可以非常方便地定制和配置缓存。绶存可以极大的提升查询效率。●MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存  ○ 默认情况下,只有一级缓存开启... 查看详情

mybatis缓存之二级缓存

二级缓存(全局缓存):基于namespace级别的缓存,一个namespace对应一个二级缓存。工作机制:一个会话,查询一条数据,这条数据会放在当前会话的一级缓存中;如果会话关闭,该会话对应的一级缓存就消失了;可以使用二级缓... 查看详情