Skip to content

MyBatis-Plus 逻辑删除

  逻辑删除(软删除)是指删除数据时,不真正删除数据库记录,而是通过标记字段将数据设置为"已删除"状态。MyBatis-Plus 通过 @TableLogic 注解一行搞定。

一、为什么需要逻辑删除?

物理删除 vs 逻辑删除:

  物理删除:DELETE FROM user WHERE id = 1
    优点:彻底删除,节省空间
    缺点:数据不可恢复,审计困难,关联数据可能丢失

  逻辑删除:UPDATE user SET deleted = 1 WHERE id = 1
    优点:数据可恢复,保留审计记录,关联数据安全
    缺点:占用空间,查询需额外过滤条件

二、配置方式

2.1 全局配置

yaml
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted      # 逻辑删除字段名
      logic-delete-value: 1            # 已删除值
      logic-not-delete-value: 0        # 未删除值

2.2 实体类注解

java
@Data
@TableName("user")
public class User {

    private Long id;
    private String name;

    @TableLogic
    private Integer deleted;  // 0=未删除,1=已删除
}

三、使用效果

3.1 删除操作

java
// 调用 deleteById 自动变成 UPDATE
userMapper.deleteById(1L);
// 执行 SQL:UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0

// 批量删除
userMapper.deleteBatchIds(Arrays.asList(1L, 2L, 3L));
// UPDATE user SET deleted = 1 WHERE id IN (1,2,3) AND deleted = 0

// 条件删除
userMapper.delete(new LambdaQueryWrapper<User>().gt(User::getAge, 50));
// UPDATE user SET deleted = 1 WHERE age > 50 AND deleted = 0

3.2 查询操作

java
// 所有查询自动加上 deleted = 0
userMapper.selectById(1L);
// SELECT * FROM user WHERE id = 1 AND deleted = 0

userMapper.selectList(null);
// SELECT * FROM user WHERE deleted = 0

userMapper.selectList(
    new LambdaQueryWrapper<User>().gt(User::getAge, 20)
);
// SELECT * FROM user WHERE age > 20 AND deleted = 0

3.3 更新操作

java
// 更新也自动过滤已删除数据
User user = new User();
user.setId(1L);
user.setAge(30);
userMapper.updateById(user);
// UPDATE user SET age = 30 WHERE id = 1 AND deleted = 0

四、查询已删除数据

java
// 如果确实需要查询已删除的数据,需要手动忽略逻辑删除
// 方式一:在 XML 中直接写 SQL
@Select("SELECT * FROM user WHERE deleted = 1")
List<User> selectDeleted();

// 方式二:使用 @SqlParser 注解(3.5.1+)
@InterceptorIgnore(tenantLine = "true")
List<User> selectAll();

五、逻辑删除原理

MyBatis-Plus 逻辑删除原理:

  ① 解析实体类 @TableLogic 注解
     → 获取逻辑删除字段名、已删除值、未删除值

  ② 拦截 SQL 执行
     → 通过 SqlSource 装饰器修改 SQL

  ③ DELETE 操作 → 改写为 UPDATE
     → DELETE FROM user WHERE id = 1
     → UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0

  ④ SELECT/UPDATE 操作 → 追加过滤条件
     → SELECT * FROM user WHERE age > 20
     → SELECT * FROM user WHERE age > 20 AND deleted = 0

六、注意事项

① 逻辑删除字段建议加索引
  CREATE INDEX idx_deleted ON user(deleted);

② 唯一索引注意
  如果 name 有唯一索引,逻辑删除后同名用户无法再次创建
  解决方法:使用联合唯一索引 (name, deleted)

③ 逻辑删除不支持级联
  删除主表时,子表不会自动逻辑删除,需要手动处理

④ 数据迁移
  逻辑删除的数据在迁移时需要特殊处理,建议定期归档

⑤ 物理删除怎么办?
  如果确实需要物理删除,写原生 SQL 或自定义 Mapper

七、速记总结

逻辑删除三步走:
  ① 数据库加字段:deleted TINYINT DEFAULT 0
  ② 实体类加注解:@TableLogic
  ③ 全局配置:logic-delete-value / logic-not-delete-value

效果:
  DELETE → UPDATE SET deleted = 1
  SELECT → 自动追加 AND deleted = 0

速记口诀:
  逻辑删除注解标,删改变更查追加,
  数据不丢可恢复,唯一索引要联合。

八、面试要点

问题答案要点
逻辑删除怎么实现?@TableLogic 注解,DELETE 变 UPDATE,SELECT 追加过滤
逻辑删除字段建议?添加索引,唯一索引改成联合索引
如何查询已删除数据?写原生 SQL 或自定义 Mapper