mybatis源码分析(7)-----缓存Cache(一级缓存,二级缓存)
写在前面
MyBatis 提供查询缓存,用于减轻数据库压力,提高数据库性能。
MyBatis缓存分为一级缓存和二级缓存。

通过对于Executor 的设计。也可以发现MyBatis的缓存机制(采用模板方法模式+装饰设计模式)
Executor
BaseExecutor
SimpleExecuor
BatchExecutor
ReuseExecutor
CacheExecutor
sqlSession最终持有的是Executor。sqlSession --> statementHandler --> executor(CacheExecutor),Executor的执行顺序是:
CacheExecutor(query方法,二级缓存查询)--->BaseExecutor(query方法,已经缓存查询) --> SimpleExecuor(doQuery方法,数据库查询)
一级缓存
一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。

1. 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的信息
2. 如果没有:从数据库查询,得到用户信息,将此信息存在一级缓存中
3. 如果sqlsession去执行commit操作(执行插入,更新,删除),会清空sqlsession中的缓存(这样做的目的:让缓存中永远存储的是最新信息,避免脏读)
4. 第二次发起查询用户id为1的用户信息,先去找缓存中查找,有,则获得
5.手动清空缓存simpleTempalte.clearCache()
//BaseExecutor.java 文件
@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
//检查是否存在一级缓存,如果存在直接拿取结果
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//myBatis默认开启一级缓存,会将查询数据结果,写到缓存集合中
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
二级缓存(鸡肋)
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。
1、在sqlmapconfig.xml中设置二级缓存总开关。在和spring集成中(默认是开启的)

mybatis二级缓存对细粒度的数据级别的缓存实现不好,对同时缓存较多条数据的缓存,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。需要使用三级缓存
最后还是建议,放弃二级缓存,在业务层使用可控制的缓存代替更好。(建议使用eHcache第三方作为二级缓存使用)
CacheExecutor.java 文件
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
// 检查是否存在二级缓存
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//cacheExecutor 持有的BaseExecutor 被装饰的对象
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
mybatis源码分析(7)-----缓存Cache(一级缓存,二级缓存)的更多相关文章
- Mybatis源码分析之Cache二级缓存原理 (五)
一:Cache类的介绍 讲解缓存之前我们需要先了解一下Cache接口以及实现MyBatis定义了一个org.apache.ibatis.cache.Cache接口作为其Cache提供者的SPI(Ser ...
- MyBatis源码分析(4)—— Cache构建以及应用
@(MyBatis)[Cache] MyBatis源码分析--Cache构建以及应用 SqlSession使用缓存流程 如果开启了二级缓存,而Executor会使用CachingExecutor来装饰 ...
- MyBatis 源码分析 - 缓存原理
1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...
- mybatis源码分析之06二级缓存
上一篇整合redis框架作为mybatis的二级缓存, 该篇从源码角度去分析mybatis是如何做到的. 通过上一篇文章知道,整合redis时需要在FemaleMapper.xml中添加如下配置 &l ...
- MyBatis源码分析(3)—— Cache接口以及实现
@(MyBatis)[Cache] MyBatis源码分析--Cache接口以及实现 Cache接口 MyBatis中的Cache以SPI实现,给需要集成其它Cache或者自定义Cache提供了接口. ...
- MyBatis源码分析-SQL语句执行的完整流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- Mybatis源码分析-BaseExecutor
根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下Base ...
- MyBatis 源码分析 - 映射文件解析过程
1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...
- Mybatis源码分析
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- MyBatis 源码分析-项目总览
MyBatis 源码分析-项目总览 1.概述 本文主要大致介绍一下MyBatis的项目结构.引用参考资料<MyBatis技术内幕> 此外,https://mybatis.org/mybat ...
随机推荐
- Shell-免键盘输入
Code: #!/bin/sh command1="ssh-keygen -t rsa -f /root/.ssh/id_rsa" expect -c " spawn $ ...
- HDU 1495 非常可乐(BFS倒水问题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1495 题目大意:只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101) ...
- Base64的好处
1. 昨天的<MIME笔记>中提到,MIME主要使用两种编码转换方式----Quoted-printable和Base64----将8位的非英语字符转化为7位的ASCII字符. 虽然这样的 ...
- 想弄一弄tensorflow,先弄numpy
现在晚上凉快点了, 下班回家可以学会东东了.. 这次的书是一个印度人写的. 按着示例代码弄起先.. #!/usr/bin/env python # -*- coding: utf-8 -*- impo ...
- NIO-4pipe
import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe; import org.ju ...
- Windows下 Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow
Tensorflow 需要 Python 3.5/3.6 64bit 版本: 具体的安装方式可查看:https://www.tensorflow.org/install/install_window ...
- linux shell 正则表达式(BREs,EREs,PREs)的比较
原文 : linux shell 正则表达式(BREs,EREs,PREs)差异比较 在使用 linux shell的实用程序,如awk,grep,sed等,正则表达式必不可少,他们的区别是什么 ...
- QT构造函数中*parent
程序写的多了,你会发现几乎所有的Qt类的构造函数都会有一个parent参数.这个参数通常是QObject* 或者是 QWidget* 类型的(定义新的类是通常首先初始化为0,在类的实现函数中赋值).很 ...
- HTML5 Video/Audio播放本地文件
这段时间经常看到开发者在反复询问同一个问题,为什么通过设置src属性,不能播放本地的媒体文件?例如video.src=”D:\test.mp4”. 这是因为浏览器中的JavaScript不能直接直接访 ...
- 移动App 的 ios11 和 iPhoneX 适配
原文链接:https://blog.csdn.net/lovelyelfpop/article/details/79460700 WKWebView 调用拨打电话功能 1.HTML 要标记添加标记电话 ...