MyBatis-Plus字段策略FieldStrategy实战避坑:为什么我的updateById总是不更新某些字段?
MyBatis-Plus字段策略FieldStrategy实战避坑为什么我的updateById总是不更新某些字段最近在技术社区看到不少开发者吐槽明明调用了updateById方法为什么数据库里的字段值纹丝不动这背后往往隐藏着MyBatis-Plus字段策略(FieldStrategy)的智能拦截机制。今天我们就来拆解这个看似简单却容易踩坑的更新机制让你彻底掌握字段更新的控制权。1. 问题现象那些消失的字段更新先看一个典型场景。假设我们有个用户实体类Data TableName(user) public class User { TableId private Long id; private String username; private Integer age; private String email; }当执行以下更新操作时User user new User(); user.setId(1L); user.setUsername(updatedName); // 没有设置age和email userMapper.updateById(user);你会发现username成功更新age保持原值符合预期但email被意外置为NULL这就是FieldStrategy在作祟。MyBatis-Plus默认采用NOT_NULL策略会过滤掉值为null的字段。要解决这个问题我们需要深入理解字段策略的运作机制。2. FieldStrategy核心机制解析2.1 三种策略作用域MyBatis-Plus的字段策略分为三个维度策略类型应用场景默认值insertStrategy插入操作时的字段过滤NOT_NULLupdateStrategy更新操作时的字段过滤NOT_NULLwhereStrategy条件构造时的字段过滤NOT_NULL提示全局默认策略在DbConfig类中定义可通过配置修改2.2 五种策略类型详解源码中的策略枚举定义了五种行为public enum FieldStrategy { IGNORED, // 完全忽略判断 NOT_NULL, // 非NULL判断默认 NOT_EMPTY, // 非空判断针对字符串 NEVER, // 永不参与 DEFAULT; // 跟随全局配置 }各策略对更新的影响对比策略null值处理空字符串处理适用场景IGNORED更新更新强制更新所有字段NOT_NULL跳过更新防止意外置空默认NOT_EMPTY跳过跳过字符串字段保护NEVER跳过跳过只读字段DEFAULT取决于全局取决于全局保持配置一致性3. 实战解决方案3.1 全局配置修改在application.yml中调整默认策略mybatis-plus: global-config: db-config: update-strategy: ignored # 改为忽略空值检查适用场景需要频繁全字段更新的系统明确知晓null值语义的业务注意全局修改会影响所有实体可能带来数据一致性问题3.2 字段级精准控制更推荐使用TableField注解进行细粒度控制Data TableName(user) public class User { TableId private Long id; private String username; TableField(updateStrategy FieldStrategy.IGNORED) private Integer age; TableField(updateStrategy FieldStrategy.NOT_EMPTY) private String email; }这样配置后age字段总会更新即使为nullemail只在非空时更新其他字段保持默认NOT_NULL策略3.3 动态策略切换技巧有时我们需要根据业务场景临时改变策略// 使用Wrapper实现条件更新 UpdateWrapperUser wrapper new UpdateWrapper(); wrapper.set(email, null) // 强制更新为null .eq(id, 1L); userMapper.update(null, wrapper);这种方法绕过了实体对象的策略检查适合特殊业务场景。4. 深度避坑指南4.1 常见问题排查流程当遇到字段不更新时建议按以下步骤排查检查实体类字段的TableField注解确认全局配置策略检查字段值是否为null/空字符串使用MyBatis-Plus的SQL日志查看实际执行的SQL4.2 策略组合的注意事项NOT_EMPTY对非String字段无效它只检查字符串的!null !isEmpty()NEVER的副作用标记为NEVER的字段将无法通过任何方式更新DEFAULT的继承规则字段级DEFAULT会继承全局配置但全局修改不影响已编译的类4.3 性能优化建议频繁更新的字段设为IGNORED查询条件字段适当使用NOT_NULL减少索引压力大文本字段考虑使用NEVER避免意外更新5. 最佳实践方案根据多年项目经验推荐以下配置组合基础信息实体public class BaseEntity { TableId private Long id; TableField(updateStrategy NEVER) private LocalDateTime createTime; TableField(updateStrategy IGNORED) private LocalDateTime updateTime; }业务实体示范Data TableName(order) public class Order extends BaseEntity { TableField(updateStrategy NOT_NULL) private OrderStatus status; TableField(updateStrategy NOT_EMPTY) private String remark; // 其他字段保持默认 private BigDecimal amount; }特殊场景处理// 临时忽略策略 User user new User(); user.setId(1L); user.setEmail(null); userMapper.update( null, Wrappers.UserlambdaUpdate() .set(User::getEmail, user.getEmail()) .eq(User::getId, user.getId()) );这种组合既保证了数据安全性又保留了必要的灵活性。在实际项目中建议将策略配置纳入代码评审要点避免团队成员因不理解机制而产生意外行为。