对于Mybatis-plus自动填充,在使用过程中遇到的一些问题,对官网中的一些注意事项做一些详细说明。
一般而言,我们对于需要自动填充的字段都需要进行设置,如下所示:需要设置注解填充字段 @TableField(… fill = FieldFill.INSERT)
@TableField(value = "create_user", fill = FieldFill.INSERT)
@JsonProperty(access = Access.READ_ONLY)
private Long createUser;
@TableField("create_date")
@JsonProperty(access = Access.READ_ONLY)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
@TableField(value = "update_user", fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
@TableField(value = "update_date", update = "now()",fill = FieldFill.UPDATE)
@JsonProperty(access = Access.READ_ONLY)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateDate;
然后实现实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.fillStrategy(metaObject, "createUser", Optional.ofNullable(UserThreadLocal.get()).orElse(1L));
this.fillStrategy(metaObject, "updateUser", Optional.ofNullable(UserThreadLocal.get()).orElse(1L));
}
/**
* this.fillStrategy() 想要进行填充的字段,必须在entity中属性上 添加 @TableField(.. fill = FieldFill.UPDATE) ,或者必须显性的传值且值不为null,否则 mp 会过滤掉这个字段
*
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
// 默认填充策略均为:如果属性有值则不覆盖,如果填充值为null则不填充 this.strictUpdateFill(metaObject,"updateUser",Long.class,Optional.ofNullable(UserThreadLocal.get()).orElse(1L));
// this.strictUpdateFill(metaObject,"updateDate", Date.class,new Date());
// 强制填充,不管属性是否有值
this.setFieldValByName("updateUser",Optional.ofNullable(UserThreadLocal.get()).orElse(1L),metaObject);
// 如果字段 updateDate 上面没有添加注解 @TableField(.. fill = FieldFill.UPDATE) 并且 修改时没有显性的传值,就算在这里 set,也不会更新
this.setFieldValByName("updateDate",new Date(),metaObject);
}
}
对于自动填充,官网给出了以下注意事项:
注意事项:
- 填充原理是直接给entity的属性设置值!!! 注解则是指定该属性在对应情况下必有值,如果无值则入库会是null
- MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充
- 字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段
- 填充处理器MyMetaObjectHandler在 Spring Boot 中需要声明@Component或@Bean注入
- 要想根据注解FieldFill.xxx和字段名以及字段类型来区分必须使用父类的strictInsertFill或者strictUpdateFill方法
- 不需要根据任何来区分可以使用父类的fillStrategy方法
第一点
填充原理是直接给entity的属性设置值!!! ,mp中update方式有三种,但第三种方式不行,不能触发自动填充
updateById(T entity) // 可以
update(T entity, Wrapper<T> updateWrapper) // 可以
update(Wrapper<T> updateWrapper) // 这一种不行,因为不是对entity实体对象进行操作的,是对实体对象封装操作类(updateWrapper)进行操作
注解则是指定该属性在对应情况下必有值,如果无值则入库会是null,mp对于属性为null的字段会过滤掉,最终动态生成的sql中是不会包含该属性。
第二点
MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充。
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
// 一般使用 this.fillStrategy() 或 this.strictUpdateFill() 对于需要填充的字段,如果显示的传值了,那么默认不填充,或者 填充的值为null,那也不填充
// this.strictUpdateFill(metaObject,"updateUser",Long.class,Optional.ofNullable(UserThreadLocal.get()).orElse(1L));
// this.strictUpdateFill(metaObject,"updateDate", Date.class,new Date());
// this.setFieldValByNam()强制填充,这种方式,不论需要填充的字段是否有值,都直接把填充的值,填充进去
this.setFieldValByName("updateUser",Optional.ofNullable(UserThreadLocal.get()).orElse(1L),metaObject);
// 如果字段 updateDate 上面没有添加注解 @TableField(.. fill = FieldFill.UPDATE) 并且 修改时没有显性的传值,就算在这里 set,也不会更新
this.setFieldValByName("updateDate",new Date(),metaObject);
}
第三点
字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段,对应的实体类中需要填充的字段,比如上文中的 updateDate 字段上必须要有注解 @TableField(…fill = FieldFill.UPDATE),如果没有,则不会触发自动填充
第四点
填充处理器MyMetaObjectHandler在 Spring Boot 中需要声明@Component或@Bean注入,bean注入
第五点和第六点,是对填充策略更准确的匹配,添加了字段类型的匹配规则
一般对于 createDate,updateDate 字段,会在数据库层面去生成,这样数据更加准确,基于这种情况,ORM层框架 mybatis 中更新完之后,返回的 int 的值,比如2,不能代表数据库中更新了2 条数据。
这是因为,mybatis显示更新了成功了 2 条,但是从数据库的层面来讲,类似从一个值从1改成1,其实并没有更新。