MyBatis 的一级缓存导致的数据一致性问题分析及解决方法
作者:小时候的阳光
在MySQL提交读隔离级别下,MyBatis一级缓存导致同一SqlSession内重复查询结果不更新,即使数据库已变更,下面给大家介绍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批处理模式,开启批量执行的SqlSession sqlSession = 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.**.dao mapper-locations: classpath:mapper/**/*Mapper.xml configuration: map-underscore-to-camel-case: true # 开启驼峰功能 local-cache-scope: statement
主要关注 local-cache-scope: statement
或者上面代码放弃使用批处理模式,采用同一个SqlSession下操作数据库,
或者直接使用批处理的SqlSession查询订单表。
到此,问题原因和处理说明完毕!
到此这篇关于MyBatis 的一级缓存导致的数据一致性问题分析的文章就介绍到这了,更多相关MyBatis一级缓存导致数据一致性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!