一、核心概念

1.1 什么是逻辑删除?

逻辑删除(Soft Delete)是指在数据库中不真正删除记录,而是通过一个字段(如 deleted)标记该记录是否被“删除”。这种方式可以保留数据历史,便于恢复或审计。

与之相对的是物理删除(Hard Delete),即使用 DELETE 语句从数据库中彻底移除记录。

1.2 logic-delete-valuelogic-not-delete-value

在 MyBatis-Plus 中,这两个配置用于定义逻辑删除字段的取值:

  • logic-delete-value:表示“已删除”的值(如 1
  • logic-not-delete-value:表示“未删除”的值(如 0

⚠️ 注意:这两个值必须是数据库中实际存储的值类型一致,比如数据库是 TINYINT 类型,建议使用整数;如果是 VARCHAR,可使用字符串如 "Y"/"N"


二、操作步骤(超详细)

步骤 1:数据库表结构准备

确保你的表中有一个字段用于标识删除状态,通常命名为 deletedis_deleted

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    deleted TINYINT DEFAULT 0 NOT NULL COMMENT '0:未删除, 1:已删除'
);

字段类型建议使用 TINYINT(1)INT,避免使用 BIT,兼容性更好。


步骤 2:实体类添加 @TableLogic 注解

在实体类中,为逻辑删除字段添加 @TableLogic 注解。

import com.baomidou.mybatisplus.annotation.*;

import lombok.Data;

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;

    private String name;

    private String email;

    @TableLogic // 标记为逻辑删除字段
    private Integer deleted; // 对应数据库中的 deleted 字段
}

@TableLogic 注解是启用逻辑删除的关键。


步骤 3:配置 application.yml(Spring Boot 项目)

application.yml 中配置逻辑删除的值:

mybatis-plus:
  global-config:
    db-config:
      # 逻辑已删除值(默认为 1)
      logic-delete-value: 1
      # 逻辑未删除值(默认为 0)
      logic-not-delete-value: 0

💡 如果你使用的是 1/0,可以省略此配置(因为这是默认值),但建议显式写出以增强可读性。


步骤 4:启动类或配置类启用 MyBatis-Plus

确保你的 Spring Boot 启动类或配置类启用了 MyBatis-Plus 扫描:

@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

步骤 5:使用 deleteByIdremove 方法测试

调用删除方法时,MyBatis-Plus 会自动将 deleted 字段更新为 logic-delete-value 的值。

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public void testDelete() {
        // 执行删除操作
        int result = userMapper.deleteById(1L);
        System.out.println("删除影响行数:" + result);
    }
}

执行后,SQL 实际执行的是:

UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0;

⚠️ 注意:MyBatis-Plus 在更新时会加上 AND deleted = 0 条件,防止重复删除。


步骤 6:查询时自动过滤已删除数据

所有 select 查询(包括 selectById, selectList 等)都会自动加上 AND deleted = 0 条件。

List<User> users = userMapper.selectList(null);

生成的 SQL:

SELECT id, name, email, deleted FROM user WHERE deleted = 0;

三、常见错误与解决方案

错误现象 原因 解决方案
删除操作仍为物理删除 未配置 logic-delete-value 或未加 @TableLogic 检查配置文件和注解是否正确
查询结果包含已删除数据 全局配置未生效或注解缺失 确保 @TableLogic 存在且字段名匹配
报错 Unknown column 'deleted' in 'where clause' 实体字段名与数据库不一致 使用 @TableField("is_deleted") 显式指定列名
更新操作报错 Data truncation: Incorrect integer value logic-delete-value 类型不匹配 确保配置值与数据库字段类型兼容(如 TINYINT 用 0/1)

四、注意事项

  1. 字段默认值必须为 logic-not-delete-value
    deleted DEFAULT 0,否则新插入数据可能被视为已删除。

  2. 不要手动设置 deleted 字段值
    插入数据时,不要手动赋值 deleted = 0,MyBatis-Plus 会自动处理。

  3. 避免在 WHERE 条件中手动写 deleted = 0
    框架已自动处理,重复写可能导致 SQL 错误。

  4. 批量删除也支持逻辑删除
    deleteBatchIdsdeleteByMap 等方法同样会触发逻辑删除。

  5. 逻辑删除字段不能用于 @TableField(fill = FieldFill.INSERT)
    因为 MP 会自动管理该字段,无需填充。


五、使用技巧

技巧 1:自定义逻辑删除值(非 0/1)

如果你使用字符串标记:

mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 'Y'
      logic-not-delete-value: 'N'

实体类字段改为:

@TableLogic
private String deleted; // "Y" 或 "N"

技巧 2:全局配置 vs 局部覆盖

可以在实体字段上通过 @TableLogic 指定局部值,覆盖全局配置:

@TableLogic(value = "1", delval = "0")
private Integer deleted;
  • value:未删除值(查询条件)
  • delval:已删除值(删除时设置)

⚠️ 注意:valuedelval@TableLogic 的属性,与全局配置方向相反!

技巧 3:强制物理删除(绕过逻辑删除)

使用 deleteByIdWithFill 或直接写 XML:

// 强制物理删除(不推荐)
int result = userMapper.getBaseMapper().getSqlSession().delete(
    "com.example.UserMapper.deleteById", 1L
);

或使用 Wrapper 强制更新:

LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getId, 1L).set(User::getDeleted, null);
userMapper.update(null, wrapper);

六、最佳实践与性能优化

✅ 最佳实践

  1. 统一命名规范
    所有表使用 deleted 字段,类型为 TINYINT(1),默认 0

  2. 使用默认值配置
    保持 logic-delete-value: 1logic-not-delete-value: 0,减少配置复杂度。

  3. 索引优化
    deleted 字段添加索引,尤其是大表:

    ALTER TABLE user ADD INDEX idx_deleted (deleted);
    
  4. 软删除 + 定期归档
    逻辑删除后,定期将 deleted = 1 的数据归档到历史表,提升主表性能。

  5. 审计日志结合
    配合 @TableField(fill = FieldFill.INSERT_UPDATE) 记录 delete_time

⚡ 性能优化建议

  • 避免在高频查询中使用 SELECT *deleted 字段会参与索引,尽量只查必要字段。
  • 复合索引注意顺序:如 (status, deleted, create_time),确保 deleted 在高频过滤字段之后。
  • 定期清理:对长期 deleted = 1 的数据进行归档或物理删除(需审批)。

七、总结

项目 推荐值
字段名 deleted
数据类型 TINYINT(1)
默认值 0
logic-delete-value 1
logic-not-delete-value 0
是否加索引 ✅ 建议加
是否可为空 ❌ 不可为空

✅ 掌握逻辑删除配置,是使用 MyBatis-Plus 的基础且关键技能,能有效提升数据安全性与系统可维护性。


📌 快速检查清单

  • 数据库字段存在且默认值正确
  • 实体类字段加 @TableLogic
  • application.yml 配置 logic-delete-valuelogic-not-delete-value
  • 查询和删除方法正常工作
  • 检查 SQL 日志确认是否自动加 deleted = 0 条件