解决 Mybatis-Plus 自动填充失效问题

确认版本

首先确认你的项目中使用的 mybatis-plus 版本是 3.3.0 以下还是 3.3.0 以上(包含 3.3.0),在低版本和高版本中重写 MetaObjectHandler 方法的 insertFill 和 updateFill 的写法是不同的,比如下面示例:

java 复制代码
@Bean
public MetaObjectHandler metaObjectHandler(){

    return new MetaObjectHandler() {
        @Override
        public void insertFill(MetaObject metaObject) {
            this.setFieldValByName("createdDate", new Date(), metaObject);
            this.setFieldValByName("updatedDate", new Date(), metaObject);
        }
            @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updatedDate", new Date(), metaObject);
        }
    };
}

这是使用 MyBatis-Plus 早期版本(在 3.3.0 之前)的自定义 MetaObjectHandler 实现。它使用 setFieldValByName 方法来设置 createdDateupdatedDate 字段的值。这种方法使用的是 java.util.Date 类型。

java 复制代码
    @Bean
    public MetaObjectHandler metaObjectHandler(){
        return new MetaObjectHandler() {
            @Override
            public void insertFill(MetaObject metaObject) {
                this.strictInsertFill(metaObject, "createdDate", Date.class, new Date());
                this.strictInsertFill(metaObject, "updatedDate", Date.class, new Date());
            }

            @Override
            public void updateFill(MetaObject metaObject) {
                this.strictUpdateFill(metaObject, "updatedDate",  LocalDateTime.class, LocalDateTime.now());
            }
        };
    }

这是使用 MyBatis-Plus 3.3.0 及以上版本中引入的更高级的填充策略。它使用 strictInsertFillstrictUpdateFill 方法,这些方法更加类型安全,也提供了更灵活的填充选项。此版本推荐使用 java.time.LocalDateTime 类型,这符合 Java 8 及更高版本中引入的时间 API,提供了更好的日期和时间处理能力。
详细对比:

  1. 类型安全性
    1. 第二种写法中,strictInsertFillstrictUpdateFill 方法允许你指定目标字段的数据类型(例如 LocalDateTime.class),从而避免了类型转换错误。
    2. 第一种写法中,setFieldValByName 方法需要你自己确保字段类型和赋值类型的一致性。
  2. 默认值提供方式
    1. 第二种写法中,你可以直接传递一个 LocalDateTime.now() 表达式,或者使用 lambda 表达式 () -> LocalDateTime.now() 来提供一个延迟执行的默认值。这在某些情况下可能更有用,比如当你的默认值依赖于一些业务逻辑时。
    2. 第一种写法直接使用 new Date() 创建日期实例,没有提供延迟执行的机制。
  3. 兼容性和 bug 修复
    1. 第二种写法是 MyBatis-Plus 推荐的最新实践,通常意味着它有更好的兼容性和已知问题的修复。
    2. 第一种写法可能在新版本中不再得到支持,或存在未解决的 bug,例如 fillStrategy 方法在 3.3.0 版本中有 bug。

检查配置

  1. 首先是引入高版本的 pom 依赖:
xml 复制代码
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.3.0</version>
</dependency>
  1. 编写mybatis-plus的配置类
java 复制代码
/**
 * MyBatis-Plus配置类
 */
@MapperScan("com.demo.mapper") // 定义项目中的 mapper 路径
@Configuration
public class MybatisPlusConfig {

    /**
     * mybatis-plus 自动填充配置
     */
    @Bean
    public MetaObjectHandler metaObjectHandler(){
        return new MetaObjectHandler() {
            @Override
            public void insertFill(MetaObject metaObject) {
                /**
                  * 第一个参数 metaObject 这里面包含了你传入的实体类
                  * 第二个参数要和实体类中的属性名保持一致
                  * 第三个参数要跟实体类中的属性类型保持一致
                  * 第四个参数是你设置的填充默认值
                  */      
                this.strictInsertFill(metaObject, "createdDate", Date.class, new Date());
                this.strictInsertFill(metaObject, "updatedDate", Date.class, new Date());
            }

            @Override
            public void updateFill(MetaObject metaObject) {
                this.strictUpdateFill(metaObject, "updatedDate",  Date.class, new Date());
            }
        };
    }

}
  1. 在实体类中,你需要使用 @TableField 注解来标记哪些字段需要自动填充,并指定填充的策略。
java 复制代码
public class User {
    @TableField(fill = FieldFill.INSERT)
    private String createTime;

    @TableField(fill = FieldFill.UPDATE)
    private String updateTime;

    // 其他字段...
}

delete 和 update 方法的区别

复制代码
在 MyBatis-Plus 中,`delete` 方法和 `update` 方法的行为差异主要源于它们对 `MetaObjectHandler` 中定义的自动填充逻辑的调用时机和方式的不同。
  • 对于 **update** 方法:

当你使用 update 方法时,MyBatis-Plus 会调用 MetaObjectHandlerupdateFill 方法。这是因为 update 方法本质上是一个更新操作,它会触发自动填充逻辑,尤其是那些被标记为 FieldFill.UPDATEFieldFill.INSERT_UPDATE 的字段。

  • 对于 **delete** 方法:

当使用 delete 方法时,情况就有所不同了。默认情况下,delete 方法不会触发 MetaObjectHandlerupdateFill 方法,即使你正在使用逻辑删除(即,delete 方法实际上执行的是一个 UPDATE 语句来修改一个逻辑删除标志)。这是因为在 MyBatis-Plus 的设计中,delete 方法的目的就是删除记录,无论是物理删除还是逻辑删除,它都不会触发更新字段的自动填充逻辑。

然而,当你在实体类中使用了 @TableLogic 注解并配置了逻辑删除,MyBatis-Plus 的 delete 方法会执行一个 UPDATE 语句来改变逻辑删除字段的值,但它不会执行 updateFill 方法来更新其他字段,如 updatedDate。这是 MyBatis-Plus 的设计决策,它将 deleteupdate 视为不同的操作,即使在逻辑删除的情况下,delete 方法也不会触发常规的更新字段填充。

注意事项

  • 如果你手动的设置了自动填充的值,那么 MyBatis-Plus 的自动填充策略不会覆盖这个值。
  • 字段必须声明 @TableField 注解,并设置 fill 属性来选择填充策略。
  • 填充处理器需要在 Spring Boot 中声明为 @Component@Bean
  • update(T entity, Wrapper<T> updateWrapper) 时,entity 不能为空,否则自动填充失效。
  • update(Wrapper<T> updateWrapper) 时不会自动填充,需要手动赋值字段条件。
相关推荐
李慕婉学姐4 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆5 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin6 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20056 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉6 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国6 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882486 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈7 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_997 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹7 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理