当前位置: 首页 > news >正文

MyBatis-Plus 实战踩坑:updateById 不更新 null 字段的“幽灵问题“

一、问题背景

最近在做一个采购系统的重新提交功能。业务场景是:采购员退回采购单后,删除 1 个物资明细,重新提交。

我需要把"被前端删除的明细"从 task 上"解绑"——回退到"待处理"状态。具体来说:

- source_task_id 设为 null(解除与当前 task 的关联)
- demand_pool_status 设为 '0'(回到待处理)
- 等等字段

诡异的现象 :

- updateById 返回 rows=1 (看起来更新成功了)
- 解绑后 demandPoolStatus=0 生效了 (待处理状态变更成功)
- 但 sourceTaskId 还是原来的值 (没被解绑)

二、排查过程

MyBatis-Plus 的 updateById 默认使用 FieldStrategy.NOT_NULL 策略 ——当字段值为 null 时, 不会 包含到 UPDATE SQL 中。

detail.setSourceTaskId(null); detail.setDemandPoolStatus("0"); detailMapper.updateById(detail);

生成的 SQL 是:

UPDATE zdk_purchase_detail SET demand_pool_status = '0', flow_status = '1', current_stage = 2 WHERE id = ?

没有 SET source_task_id = NULL 这部分!所以 source_task_id 在 DB 中保持原值。

三、解决方案

方案 1:使用 UpdateWrapper.set("field", null) 强制更新(推荐)

UpdateWrapper<ZdkPurchaseDetail> uw = new UpdateWrapper<>(); uw.eq("id", detailId); uw.set("source_task_id", null); uw.set("source_stage_id", null); uw.set("demand_pool_status", "0"); uw.set("flow_status", "1"); uw.set("current_stage", 2); uw.set("audit_quantity", null); uw.set("delivery_info", null); uw.set("payment_terms", null); zdkPurchaseDetailMapper.update(null, uw);

原理 : UpdateWrapper.set("field", null) 会 强制 生成 SET field = NULL 的 SQL,绕开 FieldStrategy.NOT_NULL 的检查。

方案 2:字段级配置 @TableField 注解

@TableField(value = "source_task_id", updateStrategy = FieldStrategy.IGNORED) private String sourceTaskId;

适用场景 :单个字段频繁需要 set null。

方案 3:全局配置 application.yml

mybatis-plus: global-config: db-config: field-strategy: ignored
http://www.jsqmd.com/news/1165768/

相关文章:

  • TB67H480FNG与PIC32MX470F512L电机控制方案详解
  • jstack JDK 8-21 实战:5分钟定位CPU 100%线程与死锁(附排查决策树)
  • 上海CPPM费用标准怎么理解?5800元、8800元和1500元报名费用说明
  • AI数字人营销视频制作全流程:从技术选型到生产部署
  • 医疗AI智能导诊系统:从架构设计到核心代码的工程实践
  • 不是优越感,是事实:月薪四千的她,凭什么对我大呼小叫?
  • ThreadPoolTaskExecutor vs ThreadPoolTaskScheduler 完整对比
  • AI绘画模型九鸟处理旧谱图像的技术解析与实战指南
  • 6J1电子管面包板测试指南:万用表+Python脚本实现4项关键参数自动化测量
  • iOS直播APP如何接入直播美颜SDK?开发流程详解
  • 计算机毕业设计之基于Spring的机房管理系统的设计与实现
  • 半桥驱动芯片 IR2110 实战:驱动 100V NMOS 高边开关的 4 步配置
  • 终极指南:如何快速免费解锁Cursor AI编辑器Pro功能
  • 48tools终极指南:一站式多媒体内容采集工具完整使用教程
  • 【计算机大数据毕业设计案例】基于 Python 的微博热点传播特征分析系统的设计与实现 基于 Python 的热门微博关键词挖掘分析系统(程序+文档+讲解+定制)
  • Shell结构化命令完整学习笔记
  • Ubuntu 22.04 + ROS 2 Humble 项目通过 TRAE 改成 Ubuntu 202.04 + ROS 1 Noetic 项目的SKLL技能
  • 百万级 JSON 数据同步优化:游标分页、分批聚合与断点续传
  • 如何快速掌握SRWE:打破Windows窗口限制的完整操作指南
  • 二阶倒立摆状态观测器设计:全阶与最小阶(3阶)观测器 MATLAB 实现与误差分析
  • 自己动手写一个spring之MVC_3
  • 直流负载管理优化:G6D-ASI继电器与CEC1302控制器的应用
  • Davinci
  • 消息发送的速率自适应:从固定间隔到 429 自愈的演进实践
  • 终极暗黑破坏神2现代优化方案:D2DX技术深度解析与实战指南
  • 大数据毕设选题推荐:基于 Python 的高校招聘薪资数据统计分析系统的设计与实现 基于 Python 的高校岗位分类与智能分析平台【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 手机版行情列表里品种太多太乱,福汇 手机端 MT4 交易列表怎么精简?
  • Edge 148工作区V2与Copilot新页:AI原生浏览器架构解析
  • TLA2518 ADC与MK64FX512VDC12微控制器的信号采集方案
  • AI泡沫与信贷风险:技术热潮下的金融风险分析