Mybatis-Plus更新时,如何避免字段为null导致的数据错误?

摘要:在 MyBatis-Plus开启逻辑删除 的情况下,updateById更新逻辑删除字段时, “看起来执行了但实际上没有更新”的问题是一种较为常见但不易察觉的问题。 背景: 项目中使用mybatis-plus且已开启逻辑删除: 1 myba
在 MyBatis-Plus开启逻辑删除 的情况下,updateById更新逻辑删除字段时, “看起来执行了但实际上没有更新”的问题是一种较为常见但不易察觉的问题。 背景: 项目中使用mybatis-plus且已开启逻辑删除: 1 mybatis-plus: 2 global-config: 3 db-config: 4 logic-delete-field: deleted 5 logic-delete-value: 1 6 logic-not-delete-value: 0 7 update-strategy: not_empty #更新策略只更新非空 在代码中获取记录并更新逻辑删除字段: 1 useRecord record = RecordMapper.selectOne(...); 2 record.setDeleted(1); 3 RecordMapper.updateById(record); 执行结果没有明显报错,也不会有异常日志,但实际没有更新逻辑删除字段。 如果没有记录执行返回值进行判断,将导致逻辑删除失败问题被隐藏,为后续业务埋雷。 原因分析: mybatis-plus使用逻辑删除背景下,使用updateById时,如下代码段: 1 record.setDeleted(1); 2 RecordMapper.updateById(record); 执行的sql语句是: 1 UPDATE table_name 2 SET deleted = 1 3 WHERE id = ? 4 AND deleted = 0; -- ⚠️ MyBatis-Plus 自动添加的条件 这条 SQL 在语法层面是合法的,但在 MyBatis-Plus 的设计语义中,逻辑删除并不被视为一次普通的 update 操作。 MyBatis-Plus 将“删除”与“更新”在内部逻辑上进行了区分:updateById 被设计为只能作用于“未被逻辑删除的数据”,而逻辑删除本身应通过 delete 系列方法触发。 1 -- 你期望生成的SQL(框架不会生成) 2 UPDATE record SET deleted = 1 WHERE id = ? AND deleted = 0; 3 4 -- updateById实际生成的SQL(deleted字段被剔除) 5 UPDATE record SET other_field=? WHERE id = ? AND deleted = 0; Mybatis-Plus为什么要这样设计: MyBtis-Plus 遵循 "语义隔离" 原则 操作类型框架方法SQL语义设计意图 业务更新 updateById() 修改业务字段 只改数据内容,不改数据状态 逻辑删除 deleteById() UPDATE ... SET deleted=1 标记数据为"已删除"状态 关键机制: 拦截器过滤:LogicDeleteInterceptor 会自动移除 SET 子句中的逻辑删除字段 条件追加:所有查询/更新操作都会自动追加 AND deleted = 0 单向操作:逻辑删除被视为不可逆操作(删除后不应通过业务代码恢复) 如何正确处理: 使用 MyBatis-Plus 提供的 deleteById 进行逻辑删除 1 // 框架会自动生成:UPDATE user SET deleted=1 WHERE id=? AND deleted=0 2 recordMapper.deleteById(1L);   在开启逻辑删除的前提下,deleteById 不会执行物理删除,而是由 MyBatis-Plus 自动生成逻辑删除 SQL,其语义与框架设计完全一致。
阅读全文