news 2026/9/11 12:56:46

MyBatis-Plus字段更新策略详解与实战方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MyBatis-Plus字段更新策略详解与实战方案

1. MyBatis-Plus更新策略深度解析

MyBatis-Plus作为MyBatis的增强工具包,在数据库操作层面提供了诸多便捷功能。其中字段更新策略是日常开发中最容易遇到问题的场景之一。默认情况下,MyBatis-Plus会忽略值为null的字段更新,这个设计背后有着合理的考量:

  1. 数据安全性:防止前端传递null意外覆盖数据库已有值
  2. 性能优化:减少不必要的SQL字段更新
  3. 业务合理性:null通常表示"无意义"而非"要清空"

这种策略在3.5.17版本中依然保持,对应的Spring Boot版本通常为2.7.x系列。理解这个机制需要先了解FieldStrategy枚举类,它定义了五种字段策略:

public enum FieldStrategy { IGNORED, // 忽略判断 NOT_NULL, // 非NULL判断 NOT_EMPTY, // 非空判断 DEFAULT, // 跟随全局配置 NEVER // 不加入SQL }

关键提示:在3.4.0+版本中,NOT_EMPTY对字符串还会检查blank状态

2. 四种解决方案实战指南

2.1 全局配置方案

在application.yml中设置全局策略:

mybatis-plus: global-config: db-config: update-strategy: ignored

这种方式的优缺点非常明显:

  • 优点:配置简单,一劳永逸
  • 缺点:影响所有更新操作,可能带来安全隐患

实测发现,在3.5.17版本中,这种配置会影响BaseMapper的updateById方法,但对UpdateWrapper不产生作用。如果项目中使用多种更新方式,需要特别注意这点。

2.2 字段注解方案

在实体类字段上使用@TableField注解:

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

这种方案更加精准可控:

  1. 只对特定字段生效
  2. 支持不同字段采用不同策略
  3. 与全局配置可以组合使用

踩坑记录:当字段同时设置insertStrategy和updateStrategy时,更新操作只会读取updateStrategy配置

2.3 UpdateWrapper动态方案

使用UpdateWrapper进行条件更新:

UpdateWrapper<User> wrapper = new UpdateWrapper<>(); wrapper.set("email", null) .eq("id", 1); userMapper.update(null, wrapper);

这种方法的特点是:

  • 完全绕过实体类字段策略
  • SQL直接生成SET email=null
  • 需要手动处理字段名映射问题

特别注意:在3.5.x版本中,如果wrapper.set()传入的是实体对象,仍然会受到字段策略影响。

2.4 自定义SQL方案

在Mapper.xml中编写完整SQL:

<update id="updateWithNull"> UPDATE user SET username=#{username}, phone=#{phone,jdbcType=VARCHAR}, email=NULL WHERE id=#{id} </update>

这种方案的适用场景:

  1. 需要精确控制个别字段行为
  2. 复杂更新逻辑
  3. 性能敏感型操作

3. 深度对比与选型建议

3.1 方案对比表

方案精确度侵入性维护成本适用场景
全局配置快速原型开发
字段注解常规业务开发
UpdateWrapper动态条件更新
自定义SQL最高最高最高复杂业务逻辑

3.2 版本兼容性注意事项

不同MyBatis-Plus版本存在行为差异:

  • 3.0.x:FieldStrategy枚举值较少
  • 3.4.x:引入NOT_EMPTY对字符串的blank检查
  • 3.5.x:优化了UpdateWrapper的处理逻辑

在Spring Boot集成时要注意:

  • 2.5.x → MyBatis-Plus 3.4.x
  • 2.7.x → MyBatis-Plus 3.5.x
  • 3.0.x → MyBatis-Plus 最新版

4. 生产环境实战经验

4.1 分页查询的特殊情况

当使用分页查询结合更新操作时:

Page<User> page = new Page<>(1, 10); page.addOrder(OrderItem.asc("create_time")); // 注意:null值排序在不同数据库表现不同 userMapper.selectPage(page, queryWrapper);

常见问题:

  1. MySQL中NULL在ASC排序时最先出现
  2. Oracle需要NVL函数处理
  3. 分页后再更新可能导致数据不一致

4.2 批量更新性能优化

对于批量更新null值的场景:

// 错误示范 - N+1问题 list.forEach(item -> userMapper.updateById(item)); // 正确做法 - 批量更新 userMapper.updateBatchById(list);

性能对比测试(1000条数据):

  • 单条更新:约1200ms
  • 批量更新:约200ms
  • 注意:批量更新需要开启事务

4.3 JSON字段处理技巧

当处理包含null的JSON字段时:

@TableField(typeHandler = FastjsonTypeHandler.class) private JSONObject extInfo;

使用Hutool工具类转换时:

JSONUtil.parseObj("{\"key\":null}"); // 注意:这里的null会被保留

5. 常见问题排查指南

5.1 问题现象:更新不生效

排查步骤:

  1. 检查MyBatis-Plus版本
  2. 确认全局配置是否加载
  3. 查看实体类注解
  4. 检查SQL日志输出

5.2 问题现象:NPE异常

可能原因:

  1. 实体类字段未加@TableField注解
  2. 使用LambdaUpdateWrapper时方法引用错误
  3. 类型处理器不匹配

解决方案:

// 使用Wrapper时要判空 wrapper.set(ObjectUtil.isNotNull(value), "column", value);

5.3 问题现象:字段被意外更新

防护措施:

  1. 使用@TableField(update=false)
  2. 在Wrapper中明确指定字段
  3. 启用SQL拦截器审计

6. 高级技巧与最佳实践

6.1 动态策略切换方案

通过自定义MetaObjectHandler实现:

public class CustomMetaObjectHandler implements MetaObjectHandler { @Override public void updateFill(MetaObject metaObject) { if (needUpdateNull()) { this.strictUpdateFill(metaObject, "field", String.class, null); } } }

6.2 多租户场景下的处理

在Saas系统中要注意:

  1. 租户ID字段永远不能为null
  2. 使用自动填充避免遗漏
  3. 更新前校验租户权限

6.3 审计字段的特殊处理

对于createTime/updateTime等字段:

@TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime;

即使设置为null,自动填充也会覆盖这个值

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 12:55:27

MCU关键词识别工程解析:MFCC与TFLM在Cortex-M上的实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 12:54:49

STM32F103 AB分区OTA实战:突破Flash限制的可靠升级方案

1. 为什么AB分区OTA不是“加个Bootloader”就完事——从STM32F103的硬件限制讲起你在网上搜“STM32F103 OTA”&#xff0c;十有八九会看到一堆“基于IAP的串口升级教程”&#xff0c;点进去发现&#xff1a;代码能跑&#xff0c;但一断电就回退、升级中途掉线变砖、新固件跑不起…

作者头像 李华
网站建设 2026/9/11 12:52:55

WorkBuddy连接实战:从数据源接入到故障排查的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 12:51:03

基于MCP协议让AI接管Ameba开发板的编译与烧录全流程

这篇内容其实想讲清楚一件很实在的事&#xff1a;AI 不只是能聊天、能补代码&#xff0c;它还能直接帮你把编译和烧录这条链路跑起来。我这里说的不是概念演示&#xff0c;而是把 Model Context Protocol&#xff08;MCP&#xff09;接到 Realtek Ameba 系列开发板上&#xff0…

作者头像 李华
网站建设 2026/9/11 12:50:44

CMSIS-5架构解析:嵌入式工程师的内核抽象与工程治理指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华