记一次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中,也就不会触发一级缓存。

相关推荐
邓工说电19 分钟前
智慧断路器安全吗?数据加密、离线保护与合规认证全解读
大数据·数据库·人工智能·智能断路器·炜晔科技
for_ever_love__28 分钟前
MySQL 全文索引实战:FULLTEXT、ngram 中文分词与 MATCH AGAINST 到底该怎么用
java·python·mysql·全文检索·分词·索引·ngram
java资料站32 分钟前
五、Spring AI Alibaba · Memory · Saver(短期会话)
java·spring·microsoft
adinnet202636 分钟前
企业微调大模型(Fine-tuning):先吃透 RAG 还是先训自己的模型
大数据·数据库
上位机妹子1 小时前
EF Core 两种继承映射:每层次一张表(TPH)与每类型一张表(TPT)
数据库·c#·.netcore·ef core
小马同学-1 小时前
Redis消息队列与客户端编程
数据库·redis
夜之眷属2 小时前
Core dump 崩溃排查:JVM 宕机后,那份 core 文件怎么用 gdb 还原现场
java·运维·服务器·jvm
weixin199701080162 小时前
《1688图片空间API踩坑:img.upload 与 album.* 的防盗链与CDN缓存问题》(附Python源码)
开发语言·python·缓存
波加曼大王2 小时前
# vLLM不要迷信PagedAttention神话,聊聊线上藏着的内部碎片陷阱
java·架构
SL_staff2 小时前
目标健康度自检清单:开发者视角下的目标-计划-任务链路断点诊断
java·开源·github