文章目录

  • 一级缓存
  • 二级缓存
  • 总结

对于一名程序员,缓存真的很重要,而且缓存真的是老生常谈的一个话题拉。因为它在我们的开发过程中真的是无处不在。今天LZ带大家来看一下。Mybatis是怎么实现一级缓存和二级缓存的。(自带的缓存机制)

一级缓存

存在BaseExecutor中,是全局的缓存,每次查询后将值存入BaseExecutor的localCache中。key是由ms,parameter,rowBounds和boundSql一起生成的一个值。value就是查询出来的结果。一旦有任何更新变动,就删除整个localCache。

  @Override//生成一级缓存的key的函数,有兴趣的看看,LZ不详细解释了,不是重点。public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {if (closed) {throw new ExecutorException("Executor was closed.");}CacheKey cacheKey = new CacheKey();cacheKey.update(ms.getId());cacheKey.update(rowBounds.getOffset());cacheKey.update(rowBounds.getLimit());cacheKey.update(boundSql.getSql());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();// mimic DefaultParameterHandler logicfor (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}cacheKey.update(value);}}if (configuration.getEnvironment() != null) {// issue #176cacheKey.update(configuration.getEnvironment().getId());}return cacheKey;}
//查询数据库并存入一级缓存的语句private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {List<E> list;//先放一个值占位localCache.putObject(key, EXECUTION_PLACEHOLDER);try {//查询数据list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);} finally {//删除占位的localCache.removeObject(key);}//将查询出来的结果存入一级缓存localCache.putObject(key, list);if (ms.getStatementType() == StatementType.CALLABLE) {//如果是存储过程把参数存入localOutputParameterCachelocalOutputParameterCache.putObject(key, parameter);}return list;}@Override//更新变动等语句删除缓存public int update(MappedStatement ms, Object parameter) throws SQLException {ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());if (closed) {throw new ExecutorException("Executor was closed.");}//删除一级缓存clearLocalCache();//执行语句return doUpdate(ms, parameter);}@Override//删除一级缓存public void clearLocalCache() {if (!closed) {localCache.clear();localOutputParameterCache.clear();}}

所以一级缓存的作用级别是SESSION级别的,因为一个session中存放一个Executor。而一级缓存放在Executor。

二级缓存

如果开启了二级缓存的话,你的Executor将会被装饰成CachingExecutor,二级缓存是MapperStatement级的缓存,也就是一个namespace就会有一个缓存,缓存是通过CachingExecutor来操作的。查询出来的结果会存在statement中的cache中,若有更新,删除类的操作默认就会清空该MapperStatement的cache(也可以通过修改xml中的属性,让它不执行),不会影响其他的MapperStatement

  @Overridepublic <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)throws SQLException {//获得该MappedStatement的cacheCache cache = ms.getCache();if (cache != null) {//看是否需要清除cache(在xml中可以配置flushCache属性决定何时清空cache)flushCacheIfRequired(ms);if (ms.isUseCache() && resultHandler == null) {//若开启了cache且resultHandler 为空ensureNoOutParams(ms, parameterObject, boundSql);@SuppressWarnings("unchecked")//从TransactionalCacheManager中取cacheList<E> list = (List<E>) tcm.getObject(cache, key);//若没值if (list == null) {//访问数据库list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);//存入cachetcm.putObject(cache, key, list); // issue #578 and #116}return list;}}return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);}@Overridepublic int update(MappedStatement ms, Object parameterObject) throws SQLException {//看是否需要清除cache(在xml中可以配置flushCache属性决定何时清空cache)flushCacheIfRequired(ms);return delegate.update(ms, parameterObject);}private void flushCacheIfRequired(MappedStatement ms) {//获得cacheCache cache = ms.getCache();if (cache != null && ms.isFlushCacheRequired()) {      //若需要清除,则清除cachetcm.clear(cache);}}

因同一个namespace下的MappedStatement的cache是同一个,而TransactionalCacheManager中统一管理cache是里面的属性transactionalCaches,该属性以MappedStatement中的Cache为key,TransactionalCache对象为Value。即一个namespace对应一个TransactionalCache。

public class TransactionalCacheManager {private Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>();……
}
public class TransactionalCache implements Cache {private static final Log log = LogFactory.getLog(TransactionalCache.class);//就是对应的namespace中的cacheprivate Cache delegate;//提交的时候清除cache的标志位private boolean clearOnCommit;//待提交的集合private Map<Object, Object> entriesToAddOnCommit;//未查到的key存放的集合private Set<Object> entriesMissedInCache;
}

总结

一级缓存是sqlSession级别的缓存,存放在BaseExecutor中的localCache中。查询就将结果缓存进去,一旦有更新,删除,插入类的操作就清空缓存。不同的sqlSession之间的缓存是互相不影响的。
二级缓存是namespace级别的,可以理解为一个mapper.xml文件对应一个二级缓存(不同的sqlSession之间的缓存是共享的),然后对缓存的操作是在.xml文件中的标签文件进行控制的。比如下面的代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.TDemoMapper">
<!-- 一个namespace对应一个缓存 --><resultMap id="baseMap" type="entity.TDemo"><result property="id" column="id" jdbcType="INTEGER"></result><result property="name" column="name" jdbcType="VARCHAR"></result></resultMap><!-- 执行此语句不清空缓存 --><select id="getAll" resultType="entity.TDemo" useCache="true" flushCache="false" >select * from t_demo</select></mapper>

Mybatis源码分析之(七)Mybatis一级缓存和二级缓存的实现相关推荐

  1. Mybatis源码分析第一天------Mybatis实用篇

    Mybatis源码分析第一天------Mybatis实用篇 一切最基本的操作就是参考官方文档:https://mybatis.org/mybatis-3/zh/configuration.html ...

  2. Mybatis源码分析(七)自定义缓存、分页的实现

    一.缓存 我们知道,在Mybatis中是有缓存实现的.分一级缓存和二级缓存,不过一级缓存其实没啥用.因为我们知道它是基于sqlSession的,而sqlSession在每一次的方法执行时都会被新创建. ...

  3. MyBatis源码分析-IDEA新建MyBatis源码工程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  4. 【mybatis源码分析(四)】mybatis事务实现原理

    Mybatis管理事务分为三种方式: mybatis的Transaction接口 JdbcTransaction:使用JDBC的事务管理机制,利用java.sql.Connection对象完成事务的提 ...

  5. MyBatis源码分析(一)MyBatis整体架构分析

    文章目录 系列文章索引 一.为什么要用MyBatis 1.原始JDBC的痛点 2.Hibernate 和 JPA 3.MyBatis的特点 4.MyBatis整体架构 5.MyBatis主要组件及其相 ...

  6. 源码通透-mybatis源码分析以及整合spring过程

    源码通透-mybatis源码分析以及整合spring过程 mybatis源码分析版本:mybaits3 (3.5.0-SNAPSHOT) mybatis源码下载地址:https://github.co ...

  7. MyBatis 源码分析系列文章合集

    1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...

  8. MyBatis 源码分析 - 缓存原理

    1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...

  9. MyBatis 源码分析 - SQL 的执行过程

    本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析.运 ...

  10. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

最新文章

  1. python 基本数据类型之字符串功能
  2. Dlib——C++机器学习库,有传统机器学习的,也有深度学习的
  3. Servlet的多重映射
  4. 波士顿大学研究生计算机科学专业排名,波士顿大学计算机科学排名2020年专家资讯深度分析...
  5. 【HRBUST - 1613】迷宫问题 (bfs)
  6. android xml 画下划线,android – strings.xml:如何从标记前面的空格中删除下划线?...
  7. Python学习day01_变量字符串与随机数
  8. 【输入一个数,判断是否为素数(质数)】
  9. Java链表详解--通俗易懂(超详细,含源码)
  10. XSS线上靶场---haozi
  11. ceph 写流程(1)
  12. w ndows无法连接到System,Windows无法连接到System Event Notification Service 服务
  13. 在市场买一个小鸡都要20多块,为什么加工好的童子鸡才19块?
  14. 微信群发频繁发送消息,请稍后再试?
  15. ARM之S5pv210的按键和中断部分
  16. 如何同时使用内网(本地有线连接)和外网(WLAN无线连接)
  17. Android 报错处理:All flavors must now belong to a named flavor dimension,Learn more at https://d.android
  18. LeetCode 1430. Check If a String Is a Valid Sequence from Root to Leaves Path in a Binary Tree
  19. MYSQL force index索引优化
  20. 我是如何通过命令执行到最终获取内网Root权限的

热门文章

  1. mac活动监视器_什么是活动监视器?
  2. Java LinkedList getFirst()方法与示例
  3. arduino 蓝牙示例_Arduino简单实例之八_蓝牙模块
  4. python淘宝cookies抢购_Python实现淘宝秒杀聚划算抢购自动提醒源码
  5. zabbix监控平台添加服务(http,nginx,mysql)
  6. SpringBoot 中的 3 种条件装配!
  7. 硬核Redis总结,看这篇就够了!
  8. 链表竟然比数组慢了1000多倍?(动图+性能评测)
  9. 面试官:HTTPS 为什么是安全的?说一下他的底层实现原理?
  10. Everything是如何搜索的