缓存设计

MyBatis将数据缓存设计成两级结构,分为一级缓存、二级缓存:

一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改);

二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Application应用。

MyBatis中一级缓存和二级缓存的组织如下图所示:

一级缓存的工作机制:

一级缓存是Session会话级别的,一般而言,一个SqlSession对象会使用一个Executor对象来完成会话操作,Executor对象会维护一个Cache缓存,以提高查询性能。关于一级缓存的详细实现,我已经在《深入理解mybatis原理》 MyBatis的一级缓存实现详解 及使用注意事项 一文中有非常详尽的讨论,读者可以前去了解。

二级缓存的工作机制:

如上所言,一个SqlSession对象会使用一个Executor对象来完成会话操作,MyBatis的二级缓存机制的关键就是对这个Executor对象做文章。如果用户配置了"cacheEnabled=true",那么MyBatis在为SqlSession对象创建Executor对象时,会对Executor对象加上一个装饰者:CachingExecutor,这时SqlSession使用CachingExecutor对象来完成操作请求。CachingExecutor对于查询请求,会先判断该查询请求在Application级别的二级缓存中是否有缓存结果,如果有查询结果,则直接返回缓存结果;如果缓存中没有,再交给真正的Executor对象来完成查询操作,之后CachingExecutor会将真正Executor返回的查询结果放置到缓存中,然后在返回给用户。

MyBatis的二级缓存设计得比较灵活,你可以使用MyBatis自己定义的二级缓存实现;你也可以通过实现org.apache.ibatis.cache.Cache接口自定义缓存;也可以使用第三方内存缓存库,如Memcached等,这个我们会在后续的文章中详细讨论。

二级缓存存在的问题

1.一个关于MyBatis的二级缓存的实际问题

现有AMapper.xml中定义了对数据库表 ATable 的CRUD操作,BMapper定义了对数据库表BTable的CRUD操作;
假设 MyBatis 的二级缓存开启,并且 AMapper 中使用了二级缓存,AMapper对应的二级缓存为ACache;
除此之外,AMapper 中还定义了一个跟BTable有关的查询语句,类似如下所述:

<select id="selectATableWithJoin" resultMap="BaseResultMap" useCache="true">
select * from ATable left join BTable on ....
</select>

执行以下操作:

  • 1. 执行AMapper中的"selectATableWithJoin" 操作,此时会将查询到的结果放置到AMapper对应的二级缓存ACache中;
  • 2. 执行BMapper中对BTable的更新操作(update、delete、insert)后,BTable的数据更新;
  • 3. 再执行1完全相同的查询,这时候会直接从AMapper二级缓存ACache中取值,将ACache中的值直接返回;

好,问题就出现在第3步上:

由于AMapper的“selectATableWithJoin” 对应的SQL语句需要和BTable进行join查找,而在第 2 步BTable的数据已经更新了,但是第 3 步查询的值是第 1 步的缓存值,已经极有可能跟真实数据库结果不一样,即ACache中缓存数据过期了!

总结来看,就是:

对于某些使用了 join连接的查询,如果其关联的表数据发生了更新,join连接的查询由于先前缓存的原因,导致查询结果和真实数据不同步;

从MyBatis的角度来看,这个问题可以这样表述:

对于某些表执行了更新(update、delete、insert)操作后,如何去清空跟这些表有关联的查询语句所造成的缓存;

当前的MyBatis的缓存机制不能很好地处理这一问题,下面我们将从当前的MyBatis的缓存机制入手,分析这一问题:

2. 当前MyBatis二级缓存的工作机制:

MyBatis二级缓存的一个重要特点:即松散的Cache缓存管理和维护。

一个Mapper中定义的增删改查操作只能影响到自己关联的Cache对象。如上图所示的Mapper namespace1中定义的若干CRUD语句,产生的缓存只会被放置到相应关联的Cache1中,即Mapper namespace2,namespace3,namespace4 中的CRUD的语句不会影响到Cache1。

可以看出,Mapper之间的缓存关系比较松散,相互关联的程度比较弱。

现在再回到上面描述的问题,如果我们将AMapper和BMapper共用一个Cache对象,那么,当BMapper执行更新操作时,可以清空对应Cache中的所有的缓存数据,这样的话,数据不是也可以保持最新吗?

确实这个也是一种解决方案,不过,它会使缓存的使用效率变的很低!AMapper和BMapper的任意的更新操作都会将共用的Cache清空,会频繁地清空Cache,导致Cache实际的命中率和使用率就变得很低了,所以这种策略实际情况下是不可取的。

最理想的解决方案就是:

  对于某些表执行了更新(update、delete、insert)操作后,如何去清空跟这些表有关联的查询语句所造成的缓存;

  这样,就是以很细的粒度管理MyBatis内部的缓存,使得缓存的使用率和准确率都能大大地提升。

mybatis深入理解(七)-----MyBatis缓存机制的设计与实现的更多相关文章

  1. 《深入理解mybatis原理4》 MyBatis缓存机制的设计与实现

    <深入理解mybatis原理> MyBatis缓存机制的设计与实现 本文主要讲解MyBatis非常棒的缓存机制的设计原理,给读者们介绍一下MyBatis的缓存机制的轮廓,然后会分别针对缓存 ...

  2. 《深入理解mybatis原理》 MyBatis缓存机制的设计与实现

    本文主要讲解MyBatis非常棒的缓存机制的设计原理,给读者们介绍一下MyBatis的缓存机制的轮廓,然后会分别针对缓存机制中的方方面面展开讨论. MyBatis将数据缓存设计成两级结构,分为一级缓存 ...

  3. MyBatis学习总结(七)——Mybatis缓存(转载)

      孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(七)--Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的 ...

  4. 【转】MyBatis学习总结(七)——Mybatis缓存

    [转]MyBatis学习总结(七)——Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualC ...

  5. MyBatis框架——动态SQL、缓存机制、逆向工程

    MyBatis框架--动态SQL.缓存机制.逆向工程 一.Dynamic SQL 为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句.最常用的就是:where和if标签 1.参考 ...

  6. mybatis深入理解(六)-----MyBatis的二级缓存的设计原理

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

  7. Mybatis学习系列(七)缓存机制

    Mybatis缓存介绍 MyBatis提供一级缓存和二级缓存机制. 一级缓存是Sqlsession级别的缓存,Sqlsession类的实例对象中有一个hashmap用于缓存数据.不同的Sqlsessi ...

  8. MyBatis学习总结(七)——Mybatis缓存

    一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...

  9. MyBatis学习总结(七)——Mybatis缓存

    一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...

随机推荐

  1. [记]Windows 系统下设置Nodejs NPM全局路径

    Windows下的Nodejs npm路径是appdata,担心安装的node_modules越来越多,导致C盘满,所以参考别人的博文,将node_modules安装的默认目录修改一下. 参考Wind ...

  2. 编译安装redis-3.2.9(latest stable version)

    What is the Redis? Redis is an open source (BSD licensed), in-memory data structure store, used as a ...

  3. DataTime 和 时间转化

    如果知道tostring 的字符串格式那么可以根据字符串格式转化成 DateTime string timeText = DateTime.Now.ToString("yy/MM/dd HH ...

  4. HTML+css 小组件

    1.三角 代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <t ...

  5. HashMap数据结构

    2.1 HashMap 2.1.1 HashMap介绍 先看看HashMap类头部的源码: public class HashMap<K,V> extends AbstractMap< ...

  6. 传递闭包+求概率——列项相消法lightoj1321好题

    主要是要想到边与边的通过概率是独立的,所以先求出最终的概率,然后用推出的公式求总期望即可 最终概率E[0][n-1],可以用传递闭包来做 裂项相消法都不会了.. /* 闭包上推期望 每条边都具有独立性 ...

  7. springboot下slf4j配置

    我们在引用的时候直接写 private static final Logger logger = LoggerFactory.getLogger(XXXServiceImpl.class); log. ...

  8. Extjs4 desktop 图标自动换行,横纵排列 图标大小修改

    一.图标换行 /*! * Ext JS Library 4.0 * Copyright(c) 2006-2011 Sencha Inc. * licensing@sencha.com * http:/ ...

  9. vs nuget 本地安装 nupkg包

    Install-Package fluentnhibernate -Source C:\Users\Alex\AppData\Local\NuGet\Cache\ 包名 路径

  10. iOS之CALayer属性简介

    /* CoreAnimation - CALayer.h Copyright (c) 2006-2017, Apple Inc. All rights reserved. */ #import < ...