背景
MySQL中使用delete_at(时间戳)作为逻辑删除标记
在业务中,使用逻辑删除是普遍做法,通常会使用一个名为deleted(0/1)的字段表示删除状态。
但是如果遇到有唯一约束,且可能反复删除和重新插入的表(如用户表,注销用户使用逻辑删除,同时表中有用户名的唯一索引约束)时,如果唯一键约束的对象在逻辑删除后重新插入,会遭遇主键冲突。
这时候的其中一个合理的解决方案是:使用delete_at作为逻辑删除标记,0表示未删除,使用delete操作时的时间戳作为已被删除的标记。
MyBatis-Plus的逻辑删除组件
官网组件地址:https://www.baomidou.com/pages/6b03c5/
MyBatis-Plus作为广泛使用的ORM组件,提供了方便好用的逻辑删除组件,但文档中给出的实例仅囊括了使用0/1作为逻辑删除标记的使用场景。
MyBatis-Plus的自动填充功能
官网组件地址:https://www.baomidou.com/pages/4c6bcf/
MyBatis-Plus提供了自动填充组件。在笔者的项目中,使用这个组件填充update_by(更新人)字段。但是在使用了逻辑删除组件后,调用delete()方法时,发现没有进行自动填充。
本文讨论在使用时间戳作为逻辑删除标记时,如何使用MyBatis-Plus的逻辑删除组件,同时如何解决自动填充功能失效的问题。
解决方案
如何使用@TableLogic注解为delete_at字段自动填入时间戳?
笔者的项目中有些表使用deleted字段作为逻辑删除标记,有些表使用delete_at,所以不能直接使用官网上的步骤 1: 配置com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig。因此,笔者选择了@TableLogic注解。该注解源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableLogic {
/**
* 默认逻辑未删除值(该值可无、会自动获取全局配置)
*/
String value() default "";
/**
* 默认逻辑删除值(该值可无、会自动获取全局配置)
*/
String delval() default "";
}
其中,delval
属性即为进行逻辑删除时对逻辑删除字段的填充值。而我们的需求是:填入当前时间戳,那么,直接使用MySQL中自带函数UNIX_TIMESTAMP()
即可作为delval属性的值。完整代码如下;
/**
* 删除时间节点时间戳
*/
@TableField("delete_at")
@TableLogic(value = "0", delval = "UNIX_TIMESTAMP()")
private Long deleteAt;
执行效果如下图:
解决自动填充功能失效的问题
笔者项目的PO中,使用了@TableField(fill = FieldFill.INSERT_UPDATE)
作为自动填充标记。代码如下:
/**
* 修改人
*/
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
private String updateBy;
但是发现在调用int delete(@Param("ew") Wrapper<T> queryWrapper)
方法进行删除时,虽然触发了逻辑删除功能,执行了update语句,但并没有对updateBy自动填充。
查询文档后发现在“常见问题”中有“删除接口自动填充功能失效”一节。
根据其中的提示,笔者使用了deleteById()
方法。但发现问题依旧。
后来,经过阅读源码,发现deleteById()
有2个重载方法,源码如下:
int deleteById(Serializable id);
int deleteById(T entity);
而笔者原来使用的是第一个重载方法。抱着试试看的心理,使用了第二个重载方法,后发现真的可以使用。见图:
至此,问题全部解决。
补充
关于MyBatis-Plus版本
经过翻阅其它的一些技术文章,发现“删除接口自动填充功能失效”一节中提到的“使用 deleteById
方法(推荐)”是在2022/10/01更新的,而在之前的版本中并没有这句话。推测该功能应当是在2022/10/01之前的最后一个release版本增加上去的。根据github上的Releases日志,推荐大家将自己的版本更新到3.5.1及以上,来使用新特性。