MybatisPlus 逻辑删除时实现自动填充删除时间
在原有代码上新增逻辑删除:
(1)数据库表 新增字段is_deleted
,其值为 0 表示未删除,为 1 表示已删除 ;新增删除时间字段 delete_time
。
ALTER TABLE user ADD `is_deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除(0: 未删除, 1: 已删除)';
ALTER TABLE user ADD `delete_time` datetime DEFAULT NULL COMMENT '删除日期';
(2)配置全局逻辑删除属性
在 application.yml
中配置 MyBatis-Plus 的全局逻辑删除属性:
mybatis-plus:
global-config:
db-config:
logic-delete-field: isDeleted # 全局逻辑删除字段名
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
(3)在对应实体类添加相应的字段 isDeleted
、deleteTime
,isDeleted
字段上添加@TableLogic
注解,deleteTime
字段额外添加 fill = FieldFill.UPDATE
。
@TableLogic
private Integer isDeleted;
@TableField(value = "delete_time", fill = FieldFill.UPDATE) // 标记为自动填充字段
private LocalDateTime deleteTime;
(4)使用 MybatisPlus 的自动填充字段功能
自动填充功能通过实现 com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
接口来实现。创建一个类 MyMetaObjectHandler
来实现该接口,并在其中定义插入和更新时的填充逻辑。
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
}
@Override
public void updateFill(MetaObject metaObject) {
// 当逻辑删除字段被更新为删除状态时,填充 delete_time
log.info("开始自动填充删除时间");
Object isDeleted = metaObject.getValue("isDeleted");
if (isDeleted != null && (Integer) isDeleted == 1) {
this.setFieldValByName("deleteTime", LocalDateTime.now(), metaObject);
}
}
}
由于逻辑删除是将删除操作转换为更新操作,标记记录为已删除,所以需要在 updateFill
方法内实现 deleteTime
的自动填充代码。注意,如果不增加判断条件if (isDeleted != null && (Integer) isDeleted == 1)
,非删除的更新操作也会填充删除时间字段。
错误做法
如果删除的条件复杂,需要使用 QueryWrapper
配合删除 ,如下删除时并不会自动填充删除时间。官方文档指出,删除接口自动填充功能会失效。
QueryWrapper<UserMo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("uid", uid);
queryWrapper.eq("type", 80);
UserMapper.delete(queryWrapper);
官方说明
正确做法 一
官方文档指出,可以使用 deleteById
方法 ,使用该方法逻辑删除时就可以触发自动填充字段。
int result = userMapper.deleteById(uid);
但是,直接使用deleteById(uid)
,它适合于自动填充通用的更新时间、更新作者等字段,而对于删除时间的填充,只需要在删除阶段时填充。
为了在 updateFill
方法中区别出是更新操作还是删除操作,需要借助 isDeleted
字段。同样使用deleteById()
方法,但选择如下入参为实体类的版本。
int deleteById(T entity);
新建实体类 userMo,单独设置 uid 和 isDeleted=1,updateFill
方法的参数 metaObject
会包含isDeleted
的值,isDeleted
具体存在于 metaObject
的 objectWrapper
中。
UserMo userMo = new UserMo();
userMo.setUid(uid);
userMo.setIsDeleted(1);
int result = UserMapper.deleteById(userMo);
使用 getValue 方法获取 isDeleted 的值,值为 1 表示该操作为删除操作,而不是更新。
Object isDeleted = metaObject.getValue("isDeleted");
注意,deleteById 虽然可以实现填充的效果,但是where筛选只会根据id进行删除,如果某些业务里面需要添加其他删除条件时无法实现了。
参考来源:
【mybatis-plus】mybatis-plus 删除并自动填充_logicdeletebyidwithfill-优快云博客
正确做法二
如果存在多种删除条件,不仅仅只根据 id,删除方法需要替换为update
方法,而不是 delete
方法。下面的代码采用 手动填充 删除时间字段的方式,注意,该方式无需使用 MyMetaObjectHandler
类。如果删除条件条件复杂的话,推荐使用这种方式。
public int delete(Long topicId) {
UpdateWrapper<VersionMo> wrapper = new UpdateWrapper<>();
wrapper.eq("topic_id", topicId).set("is_deleted", 1);
wrapper.setSql("delete_time = NOW()");
return vMapper.update(wrapper);
}