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

相关推荐
Database_Cool_4 分钟前
LLM 应用怎么省 Token、加速响应——阿里云 Tair 语义缓存实战
阿里云·缓存·云计算
三言老师17 分钟前
CentOS7.9:Redis 数据持久化结构化实战教程
数据库·redis·缓存
鸽芷咕18 分钟前
KingbaseES 优化器底层逻辑:等价变换如何改写 SQL,条件调度如何驱动运行时
数据库
Vect__29 分钟前
MySQL 内连接和外连接:从匹配关系到业务查询
数据库·mysql
qq_1508419933 分钟前
SQL的insert和update二合一指令
java·数据库·sql
2601_9647028938 分钟前
Claude Opus 5 API 开发实战:对话、文本生成与结构化输出
java·服务器·前端
聚焦前沿39 分钟前
水动力优化导流罩:原理、数据与实船验证
大数据·服务器·数据库·人工智能
Sayuanni%341 分钟前
Spring IOC
java·spring·rpc
风景的人生1 小时前
流式输出与springboot中的响应式编程
java·spring boot·ai编程
万联WANFLOW1 小时前
外贸独立站:服务器放海外国内后台卡,放国内海外客户打不开——这道两头难怎么破?
运维·网络·数据库·经验分享