@TableField(updateStrategy = FieldStrategy.IGNORED) 引起的数据丢失问题

背景

业务人员反映某某表数据莫名奇妙丢失了,要求系统排查。当时理解丢失是整条数据被删除了(文字表达精准的重要性/(ㄒoㄒ)/~~),于是排查所有delete相关代码,未发现异常。后经过反复沟通,业务表达的丢失是指某条记录的某两个属性值丢失,被置为null了(哭笑不得)。

于是继续排查,系统引入了mybatis-plus框架,数据表对应的实体其中有两个属性被加了 @TableField(updateStrategy = FieldStrategy.IGNORED) 引起注意。

java 复制代码
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String spclFieldName;

@TableField(updateStrategy = FieldStrategy.IGNORED)
private String valMpngFldNm;

FieldStrategy.IGNORED

通过智能助手得到的答案是:

@TableField(updateStrategy = FieldStrategy.IGNORED) 是 MyBatis-Plus 框架中的一个注解,用于指定某个字段在更新操作时的策略。

具体来说,@TableField 注解用于标识实体类中的字段与数据库表中的列之间的映射关系。而 updateStrategy 属性则用于定义在更新数据库记录时,该字段的更新策略。

FieldStrategy.IGNORED 是 updateStrategy 的一个值,它表示在更新操作中忽略该字段。这意味着,当你在使用 MyBatis-Plus 进行更新操作时,即使你为这个字段设置了新的值,MyBatis-Plus 也不会将这个字段的值更新到数据库中。

例如,假设你有一个 User 实体类,其中有一个 name 字段,并且你想在更新用户信息时忽略这个字段,那么你可以这样写:

java 复制代码
public class User {
   private Long id;
   
   @TableField(updateStrategy = FieldStrategy.IGNORED)
   private String name;
   
   // 其他字段和getter/setter方法
}

在这个例子中,即使你在更新 User 实体时设置了新的 name 值,这个值也不会被更新到数据库中。这可以用于保护某些重要字段,确保它们不会被意外修改。

而这里智能助手给的答案是错误的。当然这个单词确实也很容易让人误会,所以作者后面也抛弃了该注解。

通过mybatisplus官网查到这个注解意思:是忽略判断。而mybatisplus的默认全局判断策略是 not null判断,也就是说只有在值为非null的时候 update方法才会去修改对应的字段值。

以下为对应的源码:

Wrapper.java

java 复制代码
/**
 * 根据实体FieldStrategy属性来决定判断逻辑
 */
private boolean fieldStrategyMatch(TableInfo tableInfo, T entity, TableFieldInfo e) {
    switch (e.getWhereStrategy()) {
        case NOT_NULL:
            return Objects.nonNull(tableInfo.getPropertyValue(entity, e.getProperty()));
        case IGNORED:
            return true;
        case NOT_EMPTY:
            return StringUtils.checkValNotNull(tableInfo.getPropertyValue(entity, e.getProperty()));
        case NEVER:
            return false;
        default:
            return Objects.nonNull(tableInfo.getPropertyValue(entity, e.getProperty()));
    }
}

TableFieldInfo.java

java 复制代码
/**
 * 转换成 if 标签的脚本片段
 *
 * @param sqlScript     sql 脚本片段
 * @param property      字段名
 * @param fieldStrategy 验证策略
 * @return if 脚本片段
 */
private String convertIf(final String sqlScript, final String property, final FieldStrategy fieldStrategy) {
    if (fieldStrategy == FieldStrategy.NEVER) {
        return null;
    }
    if (isPrimitive || fieldStrategy == FieldStrategy.IGNORED) {
        return sqlScript;
    }
    if (fieldStrategy == FieldStrategy.NOT_EMPTY && isCharSequence) {
        return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null and %s != ''", property, property),
            false);
    }
    return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", property), false);
}

发现,FieldStrategy.IGNORED就是忽略判断,

所以在 使用 update方法时,虽然那两个属性值为null,但最后生成的sql是

sql 复制代码
set spclFieldName=null,valMpngFldNm=null

导致这两个属性值丢失。

解决办法是去掉这两个注解,或者使用

java 复制代码
ChainWrappers.lambdaUpdateChain(this.getBaseMapper())
                    .set(IdxDefTblPo::getPerfDivdIntoInd, "1")
                    .in(IdxDefTblPo::getIdxId, yesList)
                    .update();

指定更新的字段和条件。

相关推荐
啊吧怪不啊吧12 分钟前
极致性能的服务器Redis之String类型及相关指令介绍
网络·数据库·redis·分布式·mybatis
IUGEI1 小时前
从原理到落地:DAG在大数据SLA中的应用
java·大数据·数据结构·后端·算法
Whisper_Sy7 小时前
Flutter for OpenHarmony移动数据使用监管助手App实战 - 网络状态实现
android·java·开发语言·javascript·网络·flutter·php
乂爻yiyao8 小时前
1.1 JVM 内存区域划分
java·jvm
没有bug.的程序员8 小时前
Spring Cloud Eureka:注册中心高可用配置与故障转移实战
java·spring·spring cloud·eureka·注册中心
CryptoRzz9 小时前
如何高效接入日本股市实时数据?StockTV API 对接实战指南
java·python·kafka·区块链·状态模式·百度小程序
码农水水9 小时前
中国邮政Java面试被问:容器镜像的多阶段构建和优化
java·linux·开发语言·数据库·mysql·面试·php
若鱼19199 小时前
SpringBoot4.0新特性-BeanRegistrar
java·spring
好好研究10 小时前
SpringBoot - yml配置文件
java·spring boot·spring
学海无涯书山有路10 小时前
Android FragmentContainerView 新手详解(Java 版)
android·java·开发语言