MyBatis-Plus 之逻辑删除:@TableLogic与全局配置字段逻辑删除之优势与劣势


MyBatis-Plus 是开发里的一把好手,省了不少重复代码。今天咱们聊两个实用功能:逻辑删除批量操作。逻辑删除能让我们优雅地"删"数据,批量操作能高效处理一堆记录。直接上干货,带代码走起!

1. MyBatis-Plus 的逻辑删除

1.1 逻辑删除是啥?

逻辑删除不是真把数据从数据库删掉,而是加个标记,比如有个字段 deleted,0 表示正常,1 表示已删除。查数据时自动过滤掉 deleted=1 的,删除时改改标记就行。这样既能保留历史数据,又不影响正常查询。

1.2 配置逻辑删除

MP 的逻辑删除开箱即用,先得做点准备。

表结构 :假设有个 user 表,字段是 idusernameagedeleted(int 类型,0=正常,1=删除)。

实体类 :加个 @TableLogic 注解:

java 复制代码
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("user")
public class User {
    private Long id;
    private String username;
    private Integer age;
    @TableLogic
    private Integer deleted; // 逻辑删除字段
}

全局配置 (可选):在 application.yml 里设置默认值:

yaml 复制代码
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted  # 全局逻辑删除字段
      logic-delete-value: 1       # 删除时的值
      logic-not-delete-value: 0   # 未删除时的值

如果加了全局配置,实体类里 @TableLogic 可以不写,默认走全局设置。

Mapper :照旧继承 BaseMapper

java 复制代码
public interface UserMapper extends BaseMapper<User> {
}
1.3 实战:逻辑删除

逻辑删除用的是 deleteByIddelete 方法,MP 会自动把它转成 UPDATE 操作。

单个删除

java 复制代码
@SpringBootTest
class LogicDeleteTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void testDeleteById() {
        userMapper.deleteById(1L);
        System.out.println("ID=1 的用户被逻辑删除了!");
    }
}

跑完后,数据库里这条记录的 deleted 变成 1,但数据还在。MP 实际执行的 SQL 是:

sql 复制代码
UPDATE user SET deleted=1 WHERE id=1 AND deleted=0

条件删除

java 复制代码
@Test
void testDeleteByCondition() {
    userMapper.delete(new QueryWrapper<User>().eq("age", 25));
    System.out.println("25岁的都被逻辑删了!");
}

SQL 变成:

sql 复制代码
UPDATE user SET deleted=1 WHERE age=25 AND deleted=0
1.4 查询时自动过滤

逻辑删除的好处是查询时自动带上 deleted=0 的条件:

java 复制代码
@Test
void testSelect() {
    List<User> users = userMapper.selectList(null);
    users.forEach(System.out::println);
}

执行的 SQL 是:

sql 复制代码
SELECT id, username, age, deleted FROM user WHERE deleted=0

删掉的数据不会出现在结果里,省得你手动加条件。

1.5 想查已删除的怎么办?

如果真想查 deleted=1 的,得自定义 SQL:

java 复制代码
@Select("SELECT * FROM user WHERE deleted=1")
List<User> selectDeleted();

或者用 Wrapper 跳过逻辑删除:

java 复制代码
@Test
void testSelectWithDeleted() {
    List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("deleted", 1));
    users.forEach(System.out::println);
}
1.6 注意点
  • 逻辑删除只对 MP 自带方法生效,自定义 SQL 得自己处理 deleted
  • 配置好字段后,MP 会帮你改 INSERTUPDATE,自动填默认值(比如插入时 deleted=0)。

明白了,你想要的是基于 MyBatis-Plus 实现逻辑删除的具体优点和缺点。那我就结合 MyBatis-Plus 的特性,重新梳理一下逻辑删除的优缺点,聚焦在工具层面的实际体验。

使用 MyBatis-Plus 实现逻辑删除的优点

  1. 开箱即用,配置简单
    MyBatis-Plus 提供了 @TableLogic 注解和全局配置(logic-delete-field 等),几行代码就能启用逻辑删除。不用自己手写 SQL 的 UPDATE 和过滤逻辑,开发效率直接拉满。
  2. 自动过滤已删除数据
    调用 selectList、selectById 等内置方法时,MP 会自动在 SQL 中加上 WHERE deleted=0(或其他配置的未删除值),业务代码零改动,查询结果天然干净。
  3. 默认值自动填充
    插入数据时,MP 会自动为 deleted 字段填入未删除值(比如 0),更新时也能智能处理,减少手动维护字段的麻烦。
  4. 统一性强
    通过全局配置,所有表可以共用一套逻辑删除规则(比如字段名和删除值),团队协作时风格一致,维护成本低。
  5. 与物理删除无缝切换
    如果某张表不需要逻辑删除,去掉 @TableLogic 或调整配置,MP 就能切换成物理删除,灵活性很强。

使用 MyBatis-Plus 实现逻辑删除的缺点

  1. 自定义 SQL 不受控
    逻辑删除只对 MP 的内置方法(如 deleteById、selectList)生效,手写的 @Select 或 @Update SQL 不会自动加 deleted 条件,得自己处理,容易遗漏。
  2. 全局配置可能不够灵活
    如果项目里不同表需要不同的逻辑删除字段或值(比如有的用 is_deleted,有的用 deleted),全局配置就显得鸡肋,得在每张表单独加 @TableLogic 覆盖,略显繁琐。
  3. 性能隐患未解决
    MP 只是实现了逻辑删除的标记和过滤,数据长期积累导致的表膨胀问题它管不了,得开发者自己搞定时清理或归档,工具本身没提供解决方案。
  4. 调试复杂性增加
    因为删除操作被转成 UPDATE,日志里看到的 SQL 不像物理删除那么直观,排查问题时可能得多看几眼字段状态。
  5. 字段依赖强
    逻辑删除依赖实体类里的 deleted 字段,如果表结构没加这个字段或者字段名不一致,MP 的逻辑删除就失效,得严格对齐数据库设计。
相关推荐
zyxzyx6661 小时前
Canal 解析与 Spring Boot 整合实战
java·spring boot·后端
Studying_swz2 小时前
Spring WebFlux之流式输出
java·后端·spring
苏墨瀚2 小时前
C#语言的响应式设计
开发语言·后端·golang
苏墨瀚4 小时前
SQL语言的散点图
开发语言·后端·golang
一只韩非子9 小时前
一句话告诉你什么叫编程语言自举!
前端·javascript·后端
沈二到不行9 小时前
多头注意力&位置编码:完型填空任务
人工智能·后端·deepseek
追逐时光者9 小时前
C# 中比较实用的关键字,基础高频面试题!
后端·c#·.net
GoGeekBaird9 小时前
一文搞懂:Anthropic发布MCP重要更新,告别长连接
后端·操作系统
Asthenia041210 小时前
面试问题分析:为什么Java能实现反射机制,其他语言不行?
后端
拳布离手10 小时前
fastgpt工作流探索
后端