Mybatis-Plus更新对象时字段更新为空值的策略

文章讨论了在使用Mybatis-Plus时遇到的一个bug,即某些字段值被置空但仍保留原值。作者发现可能的原因在于Mybatis-Plus的默认字段策略。文章介绍了如何通过`@TableField`注解的`updateStrategy`属性来处理空值更新,以及提供单字段配置、全局配置和使用`UpdateWrapper`的解决方案。

测试提了个很突然的bug,将某些字段值置为 空/null,提交保存,再次查看还是保留原来的值,第一反应不应该,基本操作系统用的是mybatis-plus,要错错就早出错的怎么会等到现在呢?奇怪了!发现了,就看看吧!

通过排查代码是没什么问题!

那就是肯能是mybatis-plus有什么特殊的地方

通过了解 com.baomidou.mybatisplus.annotation.TableField

//version 3.4.1
public @interface TableField {

    FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;

    FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;

    FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;

    FieldFill fill() default FieldFill.DEFAULT;
}

有几个默认执行策略

FieldFill

描述
DEFAULT默认不处理
INSERT插入时填充字段
UPDATE更新时填充字段
INSERT_UPDATE插入和更新时填充字段

FieldStrategy

描述
IGNORED忽略该字段,不管是插入还是更新操作,都不会涉及到该字段
NOT_NULL当进行插入和更新操作时,如果该字段为 null,则会抛出异常
NOT_EMPTY当进行插入和更新操作时,如果该字段为 null 或者空字符串,则会抛出异常
DEFAULT当进行插入操作时,如果该字段为 null,则使用数据库中的默认值(如数据库字段设置了默认值);当进行更新操作时,如果该字段为 null,则保持原有值不变
NEVER永远不处理该字段,无论是插入还是更新操作,都不会涉及到该字段

注意

3.1.2 版本后 strategy 方法被弃用,更新为 insertStrategyupdateStrategywhereStrategy

/** * 字段验证策略 *

默认追随全局配置

* * @deprecated 3.1.2 , to use {@link #insertStrategy} and {@link #updateStrategy} and {@link #whereStrategy} */ @Deprecated FieldStrategy strategy() default FieldStrategy.DEFAULT;

通过上面可以参照以下方案处理 mp 执行更新操作空值的情况

方案一

单字段配置

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

单个字段比较灵活,但需要制定的很多,一般结合默认配置使用

方案二

全局配置

# yml 配置:
mybatis-plus:
  global-config:
    db-config:
      update-strategy: IGNORED

全局性配置会对所有的字段都忽略判断,如果有特殊字段处理,可以单独配置,修改字段的策略。

方案三

UpdateWrapper (3.x)

/**
 * 根据 whereEntity 条件,更新记录
 *
 * @param entity        实体对象 (set 条件值,可以为 null)
 * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
 */
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

User user = new User("id", "")
mapper.update(
   Wrappers.<User>lambdaUpdate()
           .set(User::getNickName, user.getNickName())
           .eq(User::getId, user.getId())
);
跟新指定字段

一个小建议

@Tablefield 注解中有属性:fill ,字段自动填充策略

正常情况下每一张表格都有几个固定的值,如create_time (创建时间)和 update_time(更新时间),在处理这些数据的时候,每次都要手动去设置比较烦

就可以采取fill 自动填充

@TableField(value = "create_time",fill = FieldFill.INSERT)
private Date createTime;
@TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
<think> 根据用户的问题,用户遇到了在使用MyBatis-Plus执行update操作更新值(null或字符串)报错的问题。用户引用的资料中提到了MyBatis-Plus默认的更新策略会忽略null值,但用户需要更新值(包括null和字符串)到数据库。 从引用中我们可以总结出以下几点: 1. MyBatis-Plus默认的更新策略(FieldStrategy)是NOT_NULL,即只更新非null的字段。因此,当字段值为null,不会更新字段。 2. 如果希望更新null值,可以通过设置字段更新策略为IGNORED,这样无论字段值是否为null,都会更新。 3. 同样,对于字符串,默认策略(NOT_EMPTY)也会忽略,所以也需要设置为IGNORED。 用户提到“更新值报错”,可能的原因是在更新,数据库表字段有非约束,而用户试图更新为null,导致数据库报错。但根据引用内容,更常见的问题是MyBatis-Plus不会更新null值(即不会将null值更新到数据库,而不是报错)。所以,用户的问题可能是: 情况1:用户希望更新为null,但MyBatis-Plus没有更新,导致数据库字段没有变成null(用户误以为报错)。 情况2:用户确实遇到了数据库约束导致的报错(例如,字段不允许为null,但用户试图更新为null)。 但用户的问题描述是“更新值报错”,所以重点在“报错”上。因此,我们需要考虑两种情况: A. 由于MyBatis-Plus更新策略导致没有更新值,而用户期望更新值,但数据库字段有非约束,当用户更新为空值(null或字符串),数据库报错(因为数据库约束不允许为)。 B. 用户配置了更新策略为IGNORED,使得MyBatis-Plus会将null值更新到数据库,但数据库字段不允许为null,因此报错。 然而,根据引用内容,更可能的情况是:用户希望更新值(包括null),但MyBatis-Plus默认不更新null值,所以用户需要改变更新策略。但是,如果数据库字段不允许为null,那么即使MyBatis-Plus更新了,也会触发数据库约束错误。 因此,解决步骤应该是: 1. 确认数据库表字段是否允许为null。如果字段不允许为null,那么更新为null就会报错,这应该检查业务逻辑,不应该更新为null。 2. 如果数据库字段允许为null,那么需要配置MyBatis-Plus更新策略,使其可以更新null值和字符串。 根据引用,配置更新策略的方法有两种: - 全局配置:在application.yml(或application.properties)中设置 - 局部配置:在实体类的字段上使用注解@TableField 具体做法如下: 全局配置(适用于所有字段): 在配置文件中(如application.yml)设置: ```yaml mybatis-plus: global-config: db-config: update-strategy: ignored # 低版本可能是 field-strategy ``` 注意:高版本(3.4.0+)中,属性名为`update-strategy`,低版本可能是`field-strategy`。另外,全局设置会作用于所有字段,可能会带来安全隐患(比如无意中将某些不允许为字段更新为null)。 局部配置(仅对特定字段): 在实体类的字段上添加注解: ```java @TableField(updateStrategy = FieldStrategy.IGNORED) private String name; ``` 这样,该字段就会忽略断,即使为null或字符串也会更新。 另外,如果用户需要更新字符串,默认策略(NOT_EMPTY)也会忽略字符串,所以同样需要设置IGNORED策略。 但是,用户提到“报错”,所以可能还需要考虑数据库约束问题。如果数据库字段有非约束,那么即使MyBatis-Plus执行了更新(即生成了更新为null的SQL),数据库也会报错。因此,在更新为null之前,需要确保数据库字段允许为null。 总结解决方案: 1. 检查数据库表结构,确保要更新为null或字符串的字段允许为。 2. 配置MyBatis-Plus更新策略为IGNORED(全局或局部),以便更新null和字符串。 如果数据库字段不允许为null,那么不能更新为null,否则会报错。此应调整业务逻辑,避免更新为null,或者修改数据库表结构(如果允许)使其可为null。 注意:引用中提到的报错可能是由于数据库约束导致的,而不是MyBatis-Plus本身报错。因此,需要从两个方面入手:数据库约束和MyBatis-Plus更新策略。 最后,根据引用内容,用户可能混淆了“更新后数据库还是原来的值”(因为MyBatis-Plus忽略更新)和“报错”。但用户明确说了“报错”,所以我们优先考虑数据库约束导致的错误。 因此,回答应该包括: - 检查数据库表结构,确认字段是否允许为null。 - 配置MyBatis-Plus更新策略,使其可以更新null和字符串(如果数据库允许)。 - 如果数据库不允许为null,则不能更新为null,需要调整业务逻辑或修改表结构。 同,提供配置示例。 </think>### MyBatis-Plus 更新值报错的解决方案 在使用 MyBatis-Plus 执行 `update` 操作,若遇到值(`null` 或字符串)更新报错,核心原因是 **MyBatis-Plus字段更新策略(FieldStrategy)** 与数据库约束冲突。以下是详细解决方案: --- ### 一、问题根本原因 1. **MyBatis-Plus 默认更新策略** 默认采用 `FieldStrategy.NOT_NULL` 策略:若字段值为 `null`,则忽略该字段,不生成更新 SQL。 $$ \text{更新SQL} = \begin{cases} \text{包含字段} & \text{值} \neq \text{null} \\ \text{忽略字段} & \text{值} = \text{null} \end{cases} $$ 2. **报错场景** 当主动需要将字段更新为 `null` 或字符串- 若未修改更新策略MyBatis-Plus 忽略该字段 → **数据库保留旧值**(非报错) - 若配置策略为 `IGNORED`,但数据库字段有 **非约束** → 执行 SQL 报错(如 `Column 'xxx' cannot be null`) --- ### 二、解决方案(按优先级推荐) #### ✅ 方案1:修改字段更新策略(推荐) 在实体类字段上添加注解,强制更新值: ```java public class User { @TableField(updateStrategy = FieldStrategy.IGNORED) // 忽略断 private String name; } ``` - **效果**:无论字段值是否为 `null` 或字符串,均会生成更新 SQL。 - **注意**:需确保数据库字段允许为 `null`,否则需同步修改表结构。 #### ✅ 方案2:全局配置更新策略 在 `application.yml` 中全局设置: ```yaml mybatis-plus: global-config: db-config: update-strategy: ignored # 全局忽略断 ``` - **适用场景**:所有实体类字段均需支持更新- **风险**:可能意外覆盖不应为字段。 #### ✅ 方案3:自定义 SQL 语句 在 Mapper 接口中使用自定义 SQL: ```xml <!-- UserMapper.xml --> <update id="updateWithNull"> UPDATE user SET name = #{name}, age = #{age} <!-- 显式指定所有字段 --> WHERE id = #{id} </update> ``` ```java // Java 调用 userMapper.updateWithNull(user); // 手动控制更新逻辑 ``` - **优势**:完全绕过 MyBatis-Plus更新策略限制。 --- ### 三、避坑指南 1. **数据库约束检查** 执行更新前,确认目标字段是否允许为 `null`: ```sql SHOW CREATE TABLE user; -- 检查字段的 NULL 约束 ``` 若字段有 `NOT NULL` 约束,需先修改表结构: ```sql ALTER TABLE user MODIFY COLUMN name VARCHAR(255) NULL; ``` 2. **版本兼容性** - MyBatis-Plus ≥ 3.4.0:使用 `@TableField(updateStrategy)` - MyBatis-Plus < 3.4.0:使用 `@TableField(strategy = FieldStrategy.IGNORED)` 3. **批量更新策略** 使用 `updateBatchById()` ,需为 **每个字段** 单独配置 `updateStrategy`。 --- ### 总结流程 ```mermaid graph TD A[遇到更新报错] --> B{数据库字段是否允许为?} B -->|是| C[配置字段策略为 IGNORED] B -->|否| D[修改数据库字段约束] D --> C C --> E[重新执行更新操作] ``` 通过调整更新策略或数据库约束,即可解决更新报错问题。优先推荐**方案1**,安全性更高[^1][^2][^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值