当前位置: 首页 > news >正文

mybatis的缓存机制

视频教程_免费高速下载|百度网盘-分享无限制 (baidu.com)

MyBatis 有一套灵活而强大的缓存机制,主要分为两级缓存:一级缓存(本地缓存)和二级缓存(全局缓存)。

  1. 一级缓存(本地缓存)

    • 一级缓存是 MyBatis 默认开启的缓存,它指的是在同一个 SqlSession 中执行相同 SQL 语句时,第一次查询的结果会被缓存起来,后续再执行相同的查询,直接从缓存中获取结果,而不再去查询数据库。

    • 一级缓存是基于 SqlSession 的生命周期的,当 SqlSession 关闭时,一级缓存也就失效了。

    • 一级缓存可以通过清空缓存或提交事务来手动刷新,默认情况下,只要 SqlSession执行一条语句,就会刷新,不会等到 SqlSession结束(不像二级缓存)

    • 一级缓存,在进行DML操作后,会使得缓存失效

    • 一个会话DML操作只会重置当前会话的缓存,不会重置其他会话的缓存,也就是说,其他会话缓存是不会更新的!

  2. 二级缓存(全局缓存)

    • 二级缓存是全局缓存,可以跨多个 SqlSession 共享缓存,但是只有当一个SqlSession结束之后会刷新二级缓存。所以当 SqlSession1和 SqlSession2都没结束且查询同样内容的时候,不会调用二级缓存,因为二级缓存啥都没有。

    • 二级缓存需要在 MyBatis 的配置文件中进行配置启用,并且需要在映射文件中指定哪些语句使用二级缓存。

      不希望某个方法开启缓存呢?我们可以添加useCache属性来关闭缓存:

      <select id="getStudentBySid" resultType="Student" useCache="false">select * from student where sid = #{sid}
      </select>
    • 对于同一个 namespace 下的语句,如果开启了二级缓存,它们的查询结果会被缓存在一个全局的缓存区域中,当其他 SqlSession 执行相同的查询时,可以从全局缓存中获取结果。

    • 二级缓存是基于 namespace 级别的,不同的 namespace 有独立的缓存区域,它们之间不会相互影响。

    • 二级缓存默认是开启的,但需要在映射文件中明确指定 <cache/> 元素,才会对该 namespace 启用缓存。

      <mapper namespace="com.example.BlogMapper"><cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/><!-- 其他映射语句 -->
      </mapper>
      

      namespace="com.example.BlogMapper":指定缓存的 namespace,即当前映射文件所属的命名空间。这个命名空间用于标识二级缓存的作用范围,是一个唯一的标识符,通常与映射器接口或者类的全路径名相对应。eviction="FIFO":指定缓存的淘汰策略。在这里,FIFO 表示采用先进先出(First In, First Out)策略,即最先进入缓存的数据最先被淘汰。flushInterval="60000":指定缓存刷新的时间间隔,单位为毫秒。在这里,设置为 60000 毫秒,即 60 秒,表示 MyBatis 会定期刷新缓存,清理过期的缓存项。size="512":指定缓存的最大项数。当缓存中的项数达到设定的值时,MyBatis 会尝试清理缓存。readOnly="true":指定是否只读。设置为 true 时,表示缓存只读,不会修改缓存中的数据,可以提高性能。默认值为 falsereadOnly="true":指定是否只读。设置为 true 时,表示缓存只读,不会修改缓存中的数据,可以提高性能。默认值为 false

    • 二级缓存的实现是可插拔的,可以自定义缓存实现,如使用 Ehcache、Redis 等。

    • 添加了二级缓存之后,会先从二级缓存中查找数据,当二级缓存中没有时,才会从一级缓存中获取,当一级缓存中都还没有数据时,才会请求数据库

需要注意的是,缓存机制虽然能提高查询性能,但在一些更新操作(例如插入、更新、删除)时,可能会导致缓存的数据不一致。因此,在执行这类操作时,MyBatis 会自动清空相关的缓存,保证数据的正确性。开发者也可以通过手动清理缓存来控制缓存的行为。

虽然缓存机制给我们提供了很大的性能提升,但是缓存存在一个问题,我们之前在计算机组成原理中可能学习过缓存一致性问题,也就是说当多个CPU在操作自己的缓存时,可能会出现各自的缓存内容不同步的问题,而Mybatis也会这样,我们来看看这个例子:

public static void main(String[] args) throws InterruptedException {try (SqlSession sqlSession = MybatisUtil.getSession(true)){TestMapper testMapper = sqlSession.getMapper(TestMapper.class);while (true){Thread.sleep(3000);System.out.println(testMapper.getStudentBySid(1));}}
}

我们现在循环地每三秒读取一次,而在这个过程中,我们使用IDEA手动修改数据库中的数据,将1号同学的学号改成100.

结果是依小明的sid并没有发生改变,这也证明了Mybatis的缓存在生效,因为我们是从外部进行修改,Mybatis不知道我们修改了数据,所以依然在使用缓存中的数据,但是这样很明显是不正确的,因此,如果存在多台服务器或者是多个程序都在使用Mybatis操作同一个数据库,并且都开启了缓存,需要解决这个问题,要么就得关闭Mybatis的缓存来保证一致性

<settings><setting name="cacheEnabled" value="false"/>
</settings>

cacheEnabled 是一个全局开关,用于控制是否开启缓存。在这里,将其值设置为 false,表示禁用缓存。 

<select id="getStudentBySid" resultType="Student" useCache="false" flushCache="true">select * from student where sid = #{sid}
</select>
  • useCache="false":这个属性用于指定是否使用缓存。在这里,useCache 被设置为 false,表示禁用缓存。即使全局缓存配置是启用的,这个查询也不会使用缓存。

  • flushCache="true":这个属性用于指定是否刷新缓存。在这里,flushCache 被设置为 true,表示在执行这个查询之前会刷新(清空)缓存。即使全局缓存是启用的,这个查询会强制刷新缓存,确保获取最新的结果。

要么就需要实现缓存共用,也就是让所有的Mybatis都使用同一个缓存进行数据存取,在后面,我们会继续学习Redis、Ehcache、Memcache等缓存框架,通过使用这些工具,就能够很好地解决缓存一致性问题

 

相关文章:

  • vue中合并下载打包视频图片
  • Gitee Reward让开源作者不再为爱发电
  • 数组练习 Leetcode 566.重塑矩阵
  • Pytest插件pytest-django让Django测试更高效
  • Spring data都包含哪些内容
  • 100天精通Python(实用脚本篇)——第113天:基于Tesseract-OCR实现OCR图片文字识别实战
  • 蓝桥杯官网填空题(海盗与金币)
  • 【C++】类和对象
  • MyBatis 的XML实现方法(JAVA)
  • Android 基础技术——addView 流程
  • vue+elenemt分页+springboot
  • 幻读是什么,用什么隔离级别可以防止幻读?
  • 解决Windows下VSCode控制台乱码问题
  • 一文了解GeoTrust SSL证书
  • Win10/11中VMware Workstation设置网络桥接模式
  • [LeetCode] Wiggle Sort
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Effective Java 笔记(一)
  • extract-text-webpack-plugin用法
  • HTTP请求重发
  • Java,console输出实时的转向GUI textbox
  • js写一个简单的选项卡
  • Redis 中的布隆过滤器
  • Redis学习笔记 - pipline(流水线、管道)
  • SQLServer之创建数据库快照
  • Webpack 4 学习01(基础配置)
  • 从零开始的无人驾驶 1
  • 回流、重绘及其优化
  • 技术发展面试
  • 实习面试笔记
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 微信支付JSAPI,实测!终极方案
  • 我有几个粽子,和一个故事
  • 正则表达式小结
  • AI算硅基生命吗,为什么?
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • 昨天1024程序员节,我故意写了个死循环~
  • ​ubuntu下安装kvm虚拟机
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #etcd#安装时出错
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (二)JAVA使用POI操作excel
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (转)c++ std::pair 与 std::make
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .Net Web项目创建比较不错的参考文章
  • .NET 材料检测系统崩溃分析