Mybatis-Plus 自动填充失效问题解决
作者:Excellent的崽子
确认版本
首先确认你的项目中使用的 mybatis-plus 版本是 3.3.0 以下还是 3.3.0 以上(包含 3.3.0),在低版本和高版本中重写 MetaObjectHandler 方法的 insertFill 和 updateFill 的写法是不同的,比如下面示例:
@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
方法来设置 createdDate
和 updatedDate
字段的值。这种方法使用的是 java.util.Date
类型。
@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 及以上版本中引入的更高级的填充策略。它使用 strictInsertFill
和 strictUpdateFill
方法,这些方法更加类型安全,也提供了更灵活的填充选项。此版本推荐使用 java.time.LocalDateTime
类型,这符合 Java 8 及更高版本中引入的时间 API,提供了更好的日期和时间处理能力。
详细对比:
类型安全性:
第二种写法中,strictInsertFill
和 strictUpdateFill
方法允许你指定目标字段的数据类型(例如 LocalDateTime.class
),从而避免了类型转换错误。
第一种写法中,setFieldValByName
方法需要你自己确保字段类型和赋值类型的一致性。
默认值提供方式:
第二种写法中,你可以直接传递一个 LocalDateTime.now()
表达式,或者使用 lambda 表达式 () -> LocalDateTime.now()
来提供一个延迟执行的默认值。这在某些情况下可能更有用,比如当你的默认值依赖于一些业务逻辑时。
第一种写法直接使用 new Date()
创建日期实例,没有提供延迟执行的机制。
兼容性和 bug 修复:
第二种写法是 MyBatis-Plus 推荐的最新实践,通常意味着它有更好的兼容性和已知问题的修复。
第一种写法可能在新版本中不再得到支持,或存在未解决的 bug,例如 fillStrategy
方法在 3.3.0 版本中有 bug。
检查配置
首先是引入高版本的 pom 依赖:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.0</version> </dependency>
编写mybatis-plus的配置类
/** * 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()); } }; } }
在实体类中,你需要使用 @TableField
注解来标记哪些字段需要自动填充,并指定填充的策略。
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 会调用 MetaObjectHandler 的 updateFill 方法。这是因为 update 方法本质上是一个更新操作,它会触发自动填充逻辑,尤其是那些被标记为 FieldFill.UPDATE 或 FieldFill.INSERT_UPDATE 的字段。
对于 delete
方法:
当使用 delete 方法时,情况就有所不同了。默认情况下,delete 方法不会触发 MetaObjectHandler 的 updateFill 方法,即使你正在使用逻辑删除(即,delete 方法实际上执行的是一个 UPDATE 语句来修改一个逻辑删除标志)。这是因为在 MyBatis-Plus 的设计中,delete 方法的目的就是删除记录,无论是物理删除还是逻辑删除,它都不会触发更新字段的自动填充逻辑。
然而,当你在实体类中使用了 @TableLogic 注解并配置了逻辑删除,MyBatis-Plus 的 delete 方法会执行一个 UPDATE 语句来改变逻辑删除字段的值,但它不会执行 updateFill 方法来更新其他字段,如 updatedDate。这是 MyBatis-Plus 的设计决策,它将 delete 和 update 视为不同的操作,即使在逻辑删除的情况下,delete 方法也不会触发常规的更新字段填充。
注意事项
- 如果你手动的设置了自动填充的值,那么 MyBatis-Plus 的自动填充策略不会覆盖这个值。
- 字段必须声明
@TableField
注解,并设置fill
属性来选择填充策略。 - 填充处理器需要在 Spring Boot 中声明为
@Component
或@Bean
。 - 在
update(T entity, Wrapper<T> updateWrapper)
时,entity
不能为空,否则自动填充失效。 - 在
update(Wrapper<T> updateWrapper)
时不会自动填充,需要手动赋值字段条件。
到此这篇关于Mybatis-Plus 自动填充失效问题解决的文章就介绍到这了,更多相关Mybatis-Plus 自动填充失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!