记一次MybatisPlus一级缓存导致的DB对象取值逻辑错误

记一次MybatisPlus一级缓存导致的DB对象取值逻辑错误

MybatisPlus我想每个做Springboot应用开发的朋友都在项目中用过,支持原生sql的编写,也提供Wrapper构造sql进行查询,还有许多封装的DAO层的service方法,对单表CRUD的支撑非常良好。Mybatis的一二级缓存大家肯定都有所耳闻,默认是开启一级缓存的,即单个sqlSession级别的缓存。可以理解为在同一个事务下,在没有执行额外增删改的情况下,相同的查询语句,从第二次开始会直接从缓存中拿第一次的查询结果。二级缓存是跨sqlSession级别的缓存,默认不开启。

场景描述

在近期的一次项目线上问题排除中,发现有两个物料计算出来放置的坐标点和预期的有所偏差,仔细核对代码后,发现逻辑无误,且通过Springboot单元测试,也能返回正确的结果。

后续在运行日志比对中,发现有一处查询物料信息的语句,没有输出对应的日志,这里首先确认了该表是开启SQL语句输出的(可以针对不同的mapper设置不同的日志输出级别,SQL输出日志级别为DEBUG,将指定mapper设置为INFO及以上级别时,就不会打印出来),那就基本可以确认是触发了Mybatis的一级缓存。

问题分析

关于Mybatis的一级缓存,可以先思考一下自己的认知在哪个程度。

缓存存在哪儿的?

第一次查询之后对象修改后是否影响第二次查询的结果?

第一次查询之后对象修改并更新到数据库后是否会触发第二次查询的一级缓存?

为什么DEBUG的时候会得出正确的结果?


其实关于这个一级缓存,在之前的项目中也遇到过类似的问题,在编码中经常会忽略这个问题,现场排查也不太好定位。首先可以确认的是第二次查询触发的一级缓存,会直接返回第一次查询结果的相同对象,意思就是第一次查询出来的结果,做了字段的set操作,是会影响到第二次查询的使用的。

我这里遇到的问题就是物料有理论宽度和视觉识别宽度,为了保证使用宽度的准确性,我会先判断有没有视觉识别宽度(相对更加准确),如果有则取二者的较大者作为物料物料宽度作为后续逻辑的输入,本身这个逻辑没啥问题,错就错在我把后续判断出来的这个有效宽度set到了原对象的理论宽度字段上,因为后续逻辑是其它同事开发的,用到的就是这个字段。

这儿的解决方案可以是将原DB查询出来的数据不做改动,深拷贝一个对象后,赋值,然后传到后续的方法中,从而不影响后续其它地方触发一级缓存的查询结果。抛开这里的这个场景,我们其它地方用到需要做字段更新,又不提交到数据库时,是否可以考虑通过DTO对象作参数或者是方法间的传输,不更新POJO时,尽量不做数据库表映射字段的set更新。

再说回为什么DEBUG的时候没有测出来的问题,很简单,因为之前DEBUG的测试方法没有标注事务注解,导致写的测试方法没有处于同一个sqlSession中,也就不会触发一级缓存。

相关推荐
小光学长1 分钟前
基于flask+vue框架的的医院预约挂号系统i1616(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库
Jelena157795857924 分钟前
使用Java爬虫获取1688 item_get_company 接口的公司档案信息
java·开发语言·爬虫
数据小小爬虫7 分钟前
Jsoup解析商品详情时,如何确保数据准确性?
java·爬虫
听封9 分钟前
✨ 索引有哪些缺点以及具体有哪些索引类型
数据库·mysql
利瑞华14 分钟前
数据库索引:缺点与类型全解析
数据库·oracle
V+zmm1013417 分钟前
自驾游拼团小程序的设计与实现(ssm论文源码调试讲解)
java·数据库·微信小程序·小程序·毕业设计
ChinaRainbowSea28 分钟前
1. Linux下 MySQL 的详细安装与使用
linux·数据库·sql·mysql·adb
坚定信念,勇往无前29 分钟前
springboot单机支持1w并发,需要做哪些优化
java·spring boot·后端
丁总学Java40 分钟前
`AdminAdminDTO` 和 `userSession` 对象中的字段对应起来的表格
java
m0_748240252 小时前
SpringMVC详解
java