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

MyBatis 的一级缓存导致的数据一致性问题分析

老生常谈的异常问题,这里记录一下,涉及MyBatis 的一级缓存和数据库隔离级别

目录

  • 问题说明
  • 问题原因
  • 问题解决

问题说明

下面一段示例的业务逻辑代码:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
@Override
public void flushOrderDetail(FlushForm form) {// 构建批量更新订单状态的参数集合List<FlushOrderParam> flushOrderParamList = payService.createFlushParam(form);// 查询出本次需要更新的订单记录List<OrderEntity> orderList = orderService.query(form);SqlSession sqlSession = null;try {// 采用MyBatis批处理模式,开启批量执行的SqlSessionsqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);// 批量处理订单状态信息orderService.batchUpdate(sqlSession, flushOrderParamList, orderList);// 提交批量处理事务sqlSession.commit();} catch (Exception e) {// 出现异常时,回滚批处理操作log.error("批处理订单状态失败", e);if (sqlSession != null) sqlSession.rollback();// 将异常抛出,触发Spring事务管理的回滚机制throw e;} finally {// 关闭SqlSession,释放资源if (sqlSession != null) {try {sqlSession.close();} catch (Exception e) {log.error("关闭sqlSession异常", e);}}}// 批量操作成功后,再次查询订单,打印订单状态日志,便于排查和验证orderList = orderService.query(form);for (OrderEntity order : orderList) {logger.debug("订单 {} 状态 {}", order.getOrderCode(), order.getStatus());}
}

上面这段Spring业务代码主要内容就是想根据参数批量更新订单状态,里面使用了Spring的事务注解,同时方法中另外开启了一个数据库会话用于批处理更新,这样可以加快速度。

这段代码连接的数据库是 MySQL, 且事务隔离级别为 提交读 (READ-COMMITTED),查询MySQL事务隔离方法如下:

SELECT @@session.transaction_isolation;

问题现象:
orderList = orderService.query(form); 查询出来的订单状态没有变化,但是数据库中已经更新 !

问题原因

并非AI 给出的回答:因为两个不同的事务管理器导致不一样的结果…

首先,在提交读的隔离级别下,即便不同的事务管理器也可以相互读取到对方数据库会话 已经提交的事务数据

那为什么读取到的最后状态没有变化? 因为 MyBatis 一级缓存导致

  • MyBatis 一级缓存默认绑定在一个 SqlSession 的生命周期内下,
  • 上面代码中的开头和结尾的 orderService.query(form) 是在同一个SqlSession生命周期下
  • 且查询参数一样,这样导致两次查询结果一样,但数据库中其实已经状态更新了

问题解决

修改一级缓存的隔离级别为 ·statement· 级别,这样等同于关闭一级缓存。

mybatis:type-aliases-package: com.middol.*.model.**.daomapper-locations: classpath:mapper/**/*Mapper.xmlconfiguration:map-underscore-to-camel-case: true # 开启驼峰功能local-cache-scope: statement

主要关注 local-cache-scope: statement

或者上面代码放弃使用批处理模式,采用同一个SqlSession下操作数据库,
或者直接使用批处理的SqlSession查询订单表。

到此,问题原因和处理说明完毕!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/257565.html

相关文章:

  • PFEIFFER普发ASM340检漏器维护保养手侧
  • 考研408《计算机组成原理》复习笔记,第三章(2)——存储器的ROM、RAM(DRAM和SRAM)、磁盘硬盘
  • 家电 EPS 内衬,重庆制造如何保障家电安全?​
  • 一站式了解RocketMQ如何实现顺序消息
  • Appium+python自动化(三十二)- PageObject+unittest
  • 树莓派超全系列教程文档--(66)rpicam-apps可用选项介绍之视频选项
  • 区块链大讲堂 | 分布式隐私计算友好的零知识证明协议
  • 举出一个异步接口测试的例子
  • 解锁数据潜能——亮数据Web数据集,精准、全面、即时
  • 阿里云获取DASHSCOPE_API_KEY教程,以及配置DASHSCOPE_API_KEY环境变量
  • 【设计模式精讲 Day 12】代理模式(Proxy Pattern)
  • 单片机测ntc热敏电阻的几种方法(软件)
  • 【C++】第十二节——详解list(上)—(list的介绍和使用、模拟实现)
  • 在Neo4j中高效处理字符串数组:完整指南与实践
  • vue | vue-macros 插件升级以及配置
  • Flink SQL解析工具类实现:从SQL到数据血缘的完整解析
  • 6.23 deque | 优先队列_堆排序 | 博弈论
  • Python 数据分析与可视化 Day 5 - 数据可视化入门(Matplotlib Seaborn)
  • 基于springboot+uniapp的“川味游”app的设计与实现7000字论文
  • go channel用法
  • 微算法科技(NASDAQ:MLGO)研发可信共识算法TCA,解决区块链微服务中的数据一致性与安全挑战
  • 拼团系统多层限流架构详解
  • 针对我的简历模拟面试
  • 采集MFC软件的数据方法记录
  • Flutter开发中记录一个非常好用的图片缓存清理的插件
  • HTML语义化标签
  • Unity编辑器扩展:UI绑定复制工具
  • AI绘画工具实测:Stable Diffusion本地部署指
  • 【目标检测】图像处理基础:像素、分辨率与图像格式解析
  • UE5 开发遇到的bug整理