1. 问题现象与背景分析
最近在项目中使用MyBatisPlus时遇到了一个诡异现象:通过Mapper查询出的实体对象数据与数据库表中的实际记录不一致。比如数据库里某条记录的status字段值为1,但通过MyBatisPlus查询出来后却变成了0。这种数据不一致问题在开发中相当危险,可能导致业务逻辑出现严重错误。
经过排查,发现这类问题通常与以下几个因素相关:
- 逻辑删除注解
@TableLogic的误用 - 字段自动填充机制的干扰
- 二级缓存或本地缓存的数据过期
- 自定义TypeHandler处理不当
- 事务隔离级别导致的脏读
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 逻辑删除导致的差异分析
2.1 @TableLogic的工作原理
@TableLogic是MyBatisPlus提供的逻辑删除注解,它的典型配置如下:
java复制@TableLogic
private Integer deleted;
当启用逻辑删除后,MyBatisPlus会自动在所有查询语句后追加WHERE deleted=0条件。如果数据库中的deleted值为1,查询时会自动过滤掉该记录。但更隐蔽的问题是:即使通过其他方式查出了记录,@TableLogic注解的字段也会被自动填充为默认值。
2.2 典型问题场景
假设数据库表结构如下:
sql复制CREATE TABLE user (
id BIGINT PRIMARY KEY,
name VARCHAR(50),
deleted TINYINT DEFAULT 0 COMMENT '0未删除 1已删除'
);
当执行以下操作时会出现数据不一致:
- 直接通过SQL更新:
UPDATE user SET deleted=1 WHERE id=1 - 然后通过MyBatisPlus查询:
java复制User user = userMapper.selectById(1L); System.out.println(user.getDeleted()); // 输出0而非数据库中的1
这是因为MyBatisPlus在结果映射阶段会强制将@TableLogic字段设置为未删除状态。
