Mybatis 缓存分析
其实本来不想专门的写一篇关于mybatis缓存的博客的。在之前的博客中已经大致的把mybatis的整体流程讲了一遍。只要按照步骤一步步的点进去,关于缓存的代码很容易就能发现。但是今天在看代码的时候突然对mybatis在缓存的设计上有点疑惑,花了点时间把它搞懂了,同时发现网上没有专门对这块作分析的,所以还是很有必要写出来和大家分享下。
缓存概述

mybatis的缓存分为一级缓存和二级缓存。一级缓存作用于sqlssesion,即一级缓存的生命周期只是在一个sql回话之内。二级缓存作用于namespace,生命周期可以看做是程序运行的生命周期。
mybatis默认不启用二级缓存,当启用二级缓存时,mybatis先去查询二级缓存,再查询一级缓存,最后才是数据库。
一级缓存

这里提到一个概念就是sqlsession,sqlsession就是一个sql回话,一个sql回话代表了一个sql连接数据库,执行,到最终commit的操作。下面请看一组测试代码
public Alarm test3() {
Alarm alarm = new Alarm();
alarm = alarmMapper.selectList(new EntityWrapper<Alarm>().eq("levels", 0)).get(0);
alarm = alarmMapper.selectList(new EntityWrapper<Alarm>().eq("levels", 0)).get(0);
return alarm;
}
大家觉得上述查询会用到一级缓存么
答案是不能,因为上述两个查询分别会创建两个sqlssesion。那我们怎么做才能共享sqlssesion呢?很简单,放到一个事物即可
@Transactional
public Alarm test3() {
Alarm alarm = new Alarm();
alarm = alarmMapper.selectList(new EntityWrapper<Alarm>().eq("levels", 0)).get(0);
alarm = alarmMapper.selectList(new EntityWrapper<Alarm>().eq("levels", 0)).get(0);
return alarm;
}
每个Sqlsseion创建的同时会伴随创建一个executor

每个executor里面都会有localCache

每次的查询缓存步骤如下图所示


上述就是mybatis的一级缓存的流程。通过上文我们知道一级缓存是由localcache储藏的。localcache实质上就是个Hashmap, mybatis将查询的结果当做localcache的value值,那么localcache的key又是什么呢?
CacheKey
接着上文的问题,localcache的key是什么呢?换言之,怎样判断某两次查询是完全相同的查询呢。
MyBatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询:
1. 传入的 statementId 2. 查询时要求的结果集中的结果范围 (结果的范围通过rowBounds.offset和rowBounds.limit表示); 3. 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() ) 4. 传递给java.sql.Statement要设置的参数值
后三条都好理解,第一条的statementId是是什么呢。如下图所示

statementId就是namespace+mapperId
接下开看下mybatis对Cachekey的定义
Cachekey的构造函数:

这些参数什么意思我们等会再说。我们看下Cachekey的创建过程。

在进行真正的查询之前,先创建出cachekey

我们再看下update方法

每增加一个条件,hashcode就会变化一次。这也能保证每个Cachekey的hashcode不一样。
二级缓存

二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
我们先来看下每次查询时二级缓存是怎么实现的
1.创建sqlsession

2.得到CacheExecutor

这里用到了一个装饰模式
我们来看具体的查询

这里的tcm就是TransactionalCacheManager

所以实际上TransactionalCacheManager的数据结构就是一个大Map里面的value也是个map。大map的key是Cache对象,小map的key就是cachekey。
我们再仔细的看下缓存的put方法
第一步

第二步,点进去

第三步

第四步

第三步中的疑问正是我之前不解的地方。解答的关键还是在cache对象上。
首先cache是通过Mapperstatement而产生的

Mapperstatement是存储在Configuration中,二级缓存和Configuration的生命周期相同,都是一整个应用的生命周期。所以这个时候推测,二级缓存实际上存放在Mapperstatement中的Cache中
那么问题又来了,二级缓存明明是存在TransactionalCacheManager中的,是怎么存到cache里面的呢。
这里就涉及到了二级缓存的另外一个特性了
只有SqlSession commit或close之后,二级缓存才会生效
我们来看代码TransactionalCache的cmmit方法

同时在TransactionalCache还有个内部类

这时候我们往上看第四步,实际上我们往TransactionalCacheManager这个大map里面存的value值就是个Addentry,这里的cache就是由MapperStatement传进来的。在最后commit的时候会把缓存值保存到cache中。这也是为什么我们还有在commit或者close的时候,二级缓存才能生效。
为什么还有close呢,

close前需要commit啊!
以上就是对mybatis缓存的一些理解。本文并没有对mybatis做出详细的描述,只是针对二级缓存的生命周期做了些研究。
参考
https://blog.csdn.net/luanlouis/article/details/41280959
https://tech.meituan.com/mybatis_cache.html
转载请标注来源: https://www.cnblogs.com/xmzJava/p/9096722.html
Mybatis 缓存分析的更多相关文章
- 【转】MaBatis学习---源码分析MyBatis缓存原理
[原文]https://www.toutiao.com/i6594029178964673027/ 源码分析MyBatis缓存原理 1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 ...
- mybatis 源码分析(四)一二级缓存分析
本篇博客主要讲了 mybatis 一二级缓存的构成,以及一些容易出错地方的示例分析: 一.mybatis 缓存体系 mybatis 的一二级缓存体系大致如下: 首先当一二级缓存同时开启的时候,首先命中 ...
- mybatis缓存源码分析之浅谈缓存设计
本文是关于mybatis缓存模块设计的读后感,关于缓存的思考,关于mybatis的缓存源码详细分析在另一篇文章:https://www.cnblogs.com/gmt-hao/p/12448896.h ...
- MyBatis的缓存分析
一:MyBatis缓存简介 MyBatis支持声明式数据缓存(declarative data caching).当一条SQL语句被标记为“可缓存”后,首次执行它时从数据库获取的所有数据会被存储在一段 ...
- mybatis缓存的设计
继续用提问的方式来看Mybatis的缓存设计. 1.Mybatis如何开启缓存 Mybatis对查询结果进行缓存,所以缓存的对象为具体的Statement 通过在Statement上是否使用缓存来启用 ...
- 聊聊MyBatis缓存机制【美团-推荐】
聊聊MyBatis缓存机制 2018年01月19日 作者: 凯伦 文章链接 18778字 38分钟阅读 前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用My ...
- MyBatis原理分析
MyBatis原理分析 参考博客: 深入理解mybatis原理: http://blog.csdn.net/luanlouis/article/details/40422941 一 . JDBC的 ...
- 聊聊MyBatis缓存机制
https://tech.meituan.com/mybatis_cache.html 前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用MyBatis的默认 ...
- Mybatis缓存 缓存配置文件 good
一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...
随机推荐
- 关于canvas补充说明
上篇文章提到的canvas画布,用到f2组件,组件地址https://gw.alipayobjects.com/os/antv/assets/f2/3.0.0/f2.js或利用npm下载:npm in ...
- LOJ-10092(最大半连通子图)
题目连通:传送门 思路: 题目定义很清晰,然后就不会了QAQ…… 后来看了书,先缩点,然后再用拓扑排序找到最长的链子的节点数(因为缩点后所有点都是一个强连通分量,所以找最长的链子就是最大限度包含 点的 ...
- 网页手机wap2.0网页的head里加入下面这条元标签,在iPhone的浏览器中页面将以原始大小显示,并不允许缩放
网页手机wap2.0网页的head里加入下面这条元标签,在iPhone的浏览器中页面将以原始大小显示,并不允许缩放. <meta name="viewport" conten ...
- JavaScript中的Undefined / Null 类型相关说明
1,综述: ※Undefined 和 Null是JavaScript中的两种数据类型(其他的类型还有:Boolean, String, Number, Object). ※Undefined类型只有一 ...
- Ubuntu搭建Anki服务器
Ubuntu搭建Anki服务器 第一步安装Anki 阿里云的服务器,xshell远程登录上 #以root用户进行操作 #安装Akni服务 easy_install AnkiServer #添加名为an ...
- IMDb、烂番茄、MTC、各种电影行业评分名字整理
这篇不是技术文章,就是对总是看到但是不知道具体是什么的一些电影名词.评分.来源,学习一下. IMDb 互联网电影资料库(Internet Movie Database,简称IMDb)是一个关于电影演员 ...
- Final——无线网络密码破解——WPA/WPA2
Final--无线网络密码破解--WPA/WPA2 20154305 齐帅 ↓ ↓ ↓ * # % & 郑 重 声 明 & % # * ↓ ↓ ↓ 本实验教程用于探索无线路由安全漏洞, ...
- python 队列结合线程的使用
from queue import Queue from threading import Thread import time q = Queue() def add_to_queue(): for ...
- python视频地址和链接
算法 链接:http://pan.baidu.com/s/1nvHmcZJ 密码:fwjg常用库 链接:http://pan.baidu.com/s/1o8uPvPg 密码:yp3w进阶-高级代码 链 ...
- web实验博客3.css-position
css-position属性为块级元素的定位提供了可能,今天我将讲述我所了解的position属性. div.h.p元素都可以称为块级元素,display属性可以改变其框类型,其值可以对框进行设置,默 ...