MyBatis-Plus 更新字段为 null 不生效?updateStrategy 一定要搞懂!

发表于 2025-10-09 23:21:17 分类于 默认分类 阅读量 66

MyBatis-Plus 更新字段为 null 不生效?updateStrategy 一定要搞懂!

💡 前言

大家在开发中肯定遇到过这样的场景:想把某个字段清空,比如“处理人”或“处理时间”,明明代码里写了 setDealTime(null),但数据库里的值却纹丝不动。

今天我就来分享我的踩坑经验,教你如何正确地把字段更新为 null,别再被 MyBatis-Plus 的默认策略坑了!


🐞 问题现场

举个真实例子,我在做工单系统,有个字段:

/**
 * 处理时间
 */
private Date dealTime;

数据库定义:

deal_time datetime DEFAULT NULL COMMENT '处理时间'

需求很简单:把这个字段清空。

于是写了这么一段代码:

Issue byId = issueService.getById(id);
byId.setDealTime(null);
issueService.updateById(byId);

结果:数据库里的 deal_time 还是之前的时间,并没有被清空!


🔍 查了 SQL 才明白

打开 SQL 日志一看:

UPDATE itsm_issue 
SET issue_code = ?, 
    update_user = ?, 
    update_time = ? 
WHERE id = ? AND is_deleted = 0

你看到了吗?deal_time 根本没出现在 SET 中!

原因就是 MyBatis-Plus 默认策略:

  • FieldStrategy.NOT_NULL
  • 也就是说:只有非 null 的字段才会参与更新
  • 所以当你 setDealTime(null) 时,它就直接跳过了这个字段

✅ 解决办法

方案 1:给字段加注解(推荐)

最直接的办法是在实体类字段上加一个注解,告诉 MyBatis-Plus:

不管值是不是 null,都参与更新

import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;

@TableField(value = "deal_time", updateStrategy = FieldStrategy.ALWAYS)
private Date dealTime;
  • ALWAYS:任何时候都更新,包括 null
  • 再执行 setDealTime(null) + updateById()
  • 生成的 SQL 会是:
UPDATE itsm_issue 
SET deal_time = ? 
WHERE id = ?
-- 参数: null

✅ 这样字段就真正清空了。


方案 2:直接用 UpdateWrapper 显式设置

如果你不想动实体类,也可以用 UpdateWrapper

UpdateWrapper<Issue> wrapper = new UpdateWrapper<>();
wrapper.eq("id", id)
       .set("deal_time", null); // 显式置空

issueMapper.update(null, wrapper);
  • 不依赖实体对象
  • SQL 直接生成 SET deal_time = NULL
  • 简单粗暴,有效 ✅

⚠️ 其他坑点

  1. 自动填充(MetaObjectHandler)

    • 如果你配置了更新自动填充:
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "dealTime", Date.class, new Date());
    }
    
    • 即使你设置了 null,也会被填成当前时间
    • 解决:加判断
    if (getFieldValByName("dealTime", metaObject) == null) {
        setFieldValByName("dealTime", new Date(), metaObject);
    }
    
  2. 前端传参问题

    • 比如 el-date-picker 默认绑定当前时间
    • 建议通过浏览器 Network 面板确认请求体,确保传递的是你想要的值

📌 小结

问题原因解决方案
setXxx(null) 不生效默认策略忽略 null给字段加 @TableField(updateStrategy = ALWAYS)
SQL 中字段没出现字段被过滤检查策略,或用 UpdateWrapper 显式设置
值被自动填充MetaObjectHandler 自动填充逻辑添加 null 判断

小建议

  • 对于“清空”字段(处理人、处理时间等),默认加上 ALWAYS
  • 自动填充逻辑谨慎,避免覆盖业务主动设置的 null
  • 开启 SQL 日志,是排查这类问题最有效的方法

🔗 参考