关于Mybatis-plus Lambda自动填充失效和条件为空报错的问题

关于Mybatis-plus Lambda自动填充失效和条件为空报错的问题

MyBatis-Plus 提供了自动填充功能,可以选择在新增或更新时自动填充指定字段;同时也提供了 基于 > Lambda 的 Wrapper 构造器使得代码更加精简。

但是,如果使用 LambdaWrapper时会出现以下两个问题:

  1. 使用 LambdaWrapper 更新部分字段,导致自动填充失效

  2. 使用 LamdaWrapper 条件为空,出现执行报 SQL 语法错误

以下,针对两种情况详细说明

使用 LambdaWrapper 更新部分字段,导致自动填充失效

自动字段填充功能,代码如下所示,可以自动在新增操作时,更新创建时间,更新操作时,更新更新时间

    /**
     * 记录创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /**
     * 记录更新时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

但是,如果使用 LambdaWrapper 进行部分字段更新,并且不传递实体对象,则无法触发自动填充,导致自动填充失效,代码如下所示

    // 更新置顶字段
    lambdaUpdate().set(topped != null, Voter::getTopped, topped)
        .eq(Voter::getId, voterId)
        .update();

原因

由于MyBatis-Plus 字段填充是必须依赖于实体对象,通过实体对象进行自动插入,如果参数中不包含实体对象,则无法触发字段自动填充

上述代码中出现了Voter::getId 但是该参数,只是作为voterId的字段映射使用,并未提供实体

官方解释 Issue 地址:Github Issue 地址

出现范围

MyBatis-Plus 中 update 方法有三种重载,分别是

    // 无参, 无法自动填充
	default UpdateChainWrapper update() {
        return ChainWrappers.updateChain(getBaseMapper());
    }
    // wrapper 作为参数,无法自动填充
        default boolean update(Wrapper updateWrapper) {
        return update(null, updateWrapper);
    }
    // 包含实体,可以自动填充
        default boolean update(T entity, Wrapper updateWrapper) {
        return SqlHelper.retBool(getBaseMapper().update(entity, updateWrapper));
    }

所以,所有 Lambda 表达式执行后使用 update 方法进行部分字段更新时,并没有实体作为参数,都会引起无法触发自动填充

而其他全量更新方法: updateById(T entity)updateById(T entity)updateBatchById(Collection entityList)saveOrUpdate(T entity)都包含了实体,不受影响

解决方案

方案一:

添加实体类作为参数,此时需要考虑更新策略

默认 MyBatis-Plus 更新策略为实体内字段如果为 null 则该字段不进行更新,此时 new Voter()就可以满足;

如果更新策略允许插入 null ,则需要查询出对应实体,再进行更新。

    // 更新置顶字段, 默认更新策略,实体字段为null 不进行更新
    lambdaUpdate().set(topped != null, Voter::getTopped, topped)
        .eq(Voter::getId, voterId)
        .update(new Voter());

    // 更新置顶字段, 更新策略,实体字段null 进行更新
    lambdaUpdate().set(topped != null, Voter::getTopped, topped)
        .eq(Voter::getId, voterId)
        .update(getById(voterId));

方案二:

使用其他全量更新方法: updateById(T entity)updateById(T entity)updateBatchById(Collection entityList)saveOrUpdate(T entity)进行更新

使用 LamdaWrapper 条件为空,出现执行报 SQL 语法错误

继续使用以上代码, 使用lambdaUpdate或者UpdateWrapper ,不添加实体作为参数, 条件更新,当topped 不为空,则更新 topped 字段。

    // 更新置顶字段, 默认更新策略,实体字段为null 不进行更新
    lambdaUpdate().set(topped != null, Voter::getTopped, topped)
        .eq(Voter::getId, voterId)
		// 无实体参数
        .update(); 

看似没有问题的代码,实际会在topped 字段为空时,报 SQL 语法错误,错误如下:

### Error updating database.  Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE (id = '1')' at line 3
### The error may exist in com/linkdood/app/mapper/VoterMapper.java (best guess)
### The error may involve com.linkdood.app.mapper.VoterMapper.update-Inline
### The error occurred while setting parameters

### SQL: UPDATE voter        WHERE (id = ?)

### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE (id = '1')' at line 3
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE (id = '1')' at line 3] with root cause

原因

从以上报错信息中可以看出,由于 topped 为空,则拼接的 sql 出现了问题,导致语法错误

出现范围

部分字段更新,且有可能条件为空,例如 PATCH接口 和 POST均可能出现该问题

解决方案

方案一: 添加实体作为参数,同样需要考虑更新策略

    // 更新置顶字段, 默认更新策略,实体字段为null 不进行更新
    lambdaUpdate().set(topped != null, Voter::getTopped, topped)
        .eq(Voter::getId, voterId)
        // 添加实体参数
        .update(new Voter()); 

方案二: 条件判断放在外面, 如果包含多个条件,条件会比较复杂

    // 更新置顶字段, 默认更新策略,实体字段为null 不进行更新
    if (topped != null) {
        lambdaUpdate().set(Voter::getTopped, topped)
                .eq(Voter::getId, voterId)
                // 无实体参数
                .update();
    }

方案三:使用其他全量更新方法: updateById(T entity)updateById(T entity)updateBatchById(Collection entityList)saveOrUpdate(T entity)进行更新

总结

该问题,Mybaits-Plus 开发者是知道的,但是因为使用情况没有普适性,均可以使用全量更新方法进行代替,所以没有作为Bug进行修复。

但是实际开发中应该熟悉以上情况的出现场景和解决方案,避免出现误以为MyBatis-Plus 帮我们做了,但是实际他又没做的情况。

---------------------
作者:assember
来源:CSDN
原文:https://blog.csdn.net/assember/article/details/108617148?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2aggregatepagefirst_rank_ecpm_v1~rank_v31_ecpm-2-108617148.pc_agg_new_rank&utm_term=LambdaUpdateWrapper%E4%B8%BA%E7%A9%BA&spm=1000.2123.3001.4430
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您好,关于mybatis-plus自动填充失效问题,可能有以下几种原因: 1. 没有正确配置自动填充插件。需要在MybatisPlusConfig类中添加自动填充插件的配置,例如: ```java @Configuration public class MybatisPlusConfig { @Bean public GlobalConfig globalConfig() { GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setMetaObjectHandler(new MyMetaObjectHandler()); return globalConfig; } } ``` 其中MyMetaObjectHandler是自定义的实现了MetaObjectHandler接口的类,用于填充实体类中的字段。 2. 实体类中没有使用注解标记需要自动填充的字段。需要在实体类中使用注解标记需要自动填充的字段,例如: ```java public class User { @TableId(type = IdType.AUTO) private Long id; private String name; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; // 省略getter和setter方法 } ``` 其中createTime字段使用了@TableField(fill = FieldFill.INSERT)注解,表示在插入数据时自动填充该字段;updateTime字段使用了@TableField(fill = FieldFill.INSERT_UPDATE)注解,表示在插入和更新数据时自动填充该字段。 3. 数据库中的字段类型与实体类中的字段类型不匹配。需要确保数据库中的字段类型与实体类中的字段类型一致,否则自动填充可能会失效。 希望以上信息能够帮助您解决mybatis-plus自动填充失效问题。 ### 回答2: Mybatis-PlusMybatis 的增强工具包,在 Mybatis 的基础上增加了许多实用的功能,其中自动填充是其非常常用的一个功能。 如果 Mybatis-Plus自动填充失效了,可能是以下原因导致的: 1. Entity 类中的字段名称和表中的列名不一致。 自动填充是依赖于 Entity 类中的字段来完成的,如果 Entity 类中的字段名称与表中的列名不一致,就会导致自动填充无法生效。 解决方法:真实名称与 Entity 类中的字段名称保持一致。 2. 自动填充字段未在表中设置默认值。 自动填充需要在表中设置默认值才能生效,如果没有设置默认值,自动填充就会失效。 解决方法:在表中设置自动填充字段的默认值。 3. 自动填充时机不对。 Mybatis-Plus自动填充有三种时机:插入时填充、更新时填充和插入或更新时填充。如果设置的时机不对,就会使自动填充无法生效。 解决方法:检查自动填充时机是否正确。 4. 自动填充类没有实现 MetaObjectHandler 接口。 自动填充是通过 MetaObjectHandler 接口来实现的,如果自动填充类没有实现该接口,就会导致自动填充失效。 解决方法:实现 MetaObjectHandler 接口,并在配置文件中配置自动填充类。 以上是 Mybatis-Plus 自动填充失效的可能原因和解决方法,根据具体情况进行排查和修复即可。 ### 回答3: mybatis-plus自动填充失效可能会有以下几个原因: 1. 没有在实体类中定义自动填充字段和注解 在使用mybatis-plus自动填充功能时,需要在实体类中定义自动填充字段,并使用注解@TableField(fill = FieldFill.INSERT_UPDATE)或@TableField(fill = FieldFill.INSERT)或@TableField(fill = FieldFill.UPDATE)注解,指定自动填充的类型。 2. mybatis-plus版本问题 如果使用的mybatis-plus版本过低,可能会导致自动填充失效。建议升级mybatis-plus的版本至最新版或者高于3.0.6版本。 3. 没有配置mybatis-plus自动填充器 在使用mybatis-plus自动填充功能时,还需要配置自动填充器。可以继承MetaObjectHandler类,并实现其中的方法,如insertFill()、updateFill()等,在这些方法中完成自动填充的逻辑。然后在Mybatis-plus的配置文件中配置自动填充器。 4. 实体类属性名和数据库字段名不一致 在mybatis-plus自动填充时,会根据实体类的定义自动填充对应的字段值。如果实体类属性名和数据库字段名不一致,可能会导致自动填充失败。可以使用@TableField(value = "数据库字段名")注解解决这个问题。 5. 数据库类型问题 mybatis-plus自动填充功能依赖于Mybatis的TypeHandler机制和JDBC驱动等技术,如果数据库类型不受支持,可能会导致自动填充失效。 总之,如果发现mybatis-plus自动填充失效,需要仔细检查以上几个问题。如果无法自行解决,可以向mybatis-plus官方社区提出问题,或者寻求专业的技术支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值