逻辑删除是一种优雅且安全的数据管理策略,它不会真正从数据库中删除记录,而是通过专用字段标记记录为已删除状态,既能保留数据历史痕迹、满足审计与数据恢复需求,又能保证正常业务查询只返回有效数据,避免物理删除导致的数据永久丢失风险。
MyBatis-Plus 对逻辑删除提供了零侵入、自动化的原生支持,无需手动编写 SQL 条件,框架会在底层自动完成逻辑删除的处理。
MyBatis-Plus 会在执行 CRUD 操作时,自动对逻辑删除字段进行拦截处理,规则如下:
核心特点:对业务代码完全透明,开发者无需修改原有逻辑,即可实现逻辑删除。
逻辑删除支持所有数据库字段类型,推荐根据业务场景选择,不同类型配置方式不同:
Integer(int)
未删除值:0
已删除值:1
优点:占用空间小、查询效率高、适配绝大多数业务场景
Boolean
未删除值:false
已删除值:true
优点:语义清晰,代码可读性高
LocalDateTime / datetime
未删除值:null
已删除值:now()(当前时间)
用途:可记录删除时间,满足审计需求
BigInt
未删除值:0
已删除值:UNIX_TIMESTAMP()(时间戳)
用途:可作为唯一索引组合字段,支持同一数据多次逻辑删除
使用前准备:数据库表必须添加逻辑删除字段(如 deleted)
全局配置(推荐,统一管理)
在 application.yml 中配置全局逻辑删除规则,所有实体类通用,无需单独注解。
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段名(实体类属性名)
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值注解局部配置(灵活定制)
不使用全局配置,在单个实体类字段上添加 @TableLogic 注解,单独配置规则。
import com.baomidou.mybatisplus.annotation.TableLogic;
public class User {
private Long id;
private String username;
// 局部逻辑删除注解
@TableLogic(value = "0", delval = "1")
private Integer deleted;
}value:逻辑未删除值(默认 0)
delval:逻辑已删除值(默认 1)
优先级:局部注解 > 全局配置,单个实体可覆盖全局规则。
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
@Data
public class User {
private Long id;
private String username;
// 全局配置下,只需添加注解即可(无需指定值)
@TableLogic
private Integer deleted;
}未删除状态
推荐 3 种方案,保证新数据默认是未删除状态:
数据库默认值(最简单):给 deleted 字段设置默认值 0
实体类默认值:private Integer deleted = 0;
自动填充功能:通过 MP 自动填充统一赋值(适合微服务统一规范)
自动生效
自动转为逻辑删除
// 调用原生删除方法,自动执行 update 标记删除
userMapper.deleteById(1L);
userService.removeById(1L);自动过滤已删除数据
// 自动拼接 where deleted = 0,只查询有效数据
userMapper.selectById(1L);
userService.list();特殊场景
如果需要查询已删除的记录,必须使用自定义 SQL,MP 不会拦截手动编写的 SQL:
@Select("select * from user where deleted = 1")
List<User> selectDeletedUsers();ID 生成器 + 逻辑删除
逻辑删除功能 与自定义 ID 生成器完全兼容,互不影响:
插入时:ID 生成器生成主键 → 逻辑删除字段赋值为未删除
删除时:仅更新逻辑删除字段,不修改主键
可在同一个项目中同时使用,无任何冲突。
未添加 @TableLogic 注解
全局配置字段名与实体类属性名不一致
使用了自定义 SQL(MP 仅拦截内置方法)
直接执行更新操作,将逻辑删除字段改为未删除值即可:
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id", 1L).set("deleted", 0);
userMapper.update(null, wrapper);如果逻辑删除字段参与唯一索引,推荐使用 时间戳类型,避免重复数据无法插入。
数据无需留存,如日志、临时缓存
超高并发写入,追求极致性能
业务上永久不需要查询历史数据
逻辑删除是标记删除而非物理删除,MP 自动拦截 CRUD 实现无侵入使用
推荐使用 Integer 类型 + 全局配置,简单高效、适配绝大多数场景
配置优先级:局部 @TableLogic 注解 > 全局配置
与自定义 ID 生成器完全兼容,可同时使用
内置方法自动生效,自定义 SQL 需手动处理逻辑删除条件