# MyBatis-Plus教程 - 10 逻辑删除

什么是逻辑删除?

  • 物理删除 :删除数据的时候,是从数据库中直接删除数据;

  • 逻辑删除 :删除数据的时候,没有从数据库删除数据,而是一列数据来标识数据被删除了,例如表中定义一个字段叫 deleted,值为0表示数据有效,值为1表示数据已经被删除。

逻辑删除利于数据的恢复,但是会长期保留大量数据,查询的时候也需要过滤掉这些数据,对于带有唯一性约束的字段,逻辑删除的记录仍然存在,可能会影响插入新数据。使用的时候需要权衡利弊。

# 10.1 实现逻辑删除

下面看一下在 MyBatis-Plus 中如何实现逻辑删除。

# 1 数据库表添加字段

先给数据库表添加一个用于标识逻辑删除的字段,我这里起名叫 deleted,名字自定义。

ALTER TABLE tb_user
ADD COLUMN deleted TINYINT(1) DEFAULT 0;
1
2

并设置默认值为0,表示没有被删除。

# 2 修改pojo

修改数据库表对应的实体类,添加 @TableLogic 注解,标识是用于逻辑删除的字段。

User.java

package com.foooor.helloplus.pojo;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;

@Data
@TableName("tb_user")
public class User {

    // ...其他属性,略
    
    @TableLogic(value="0",delval="1")
    private Integer deleted;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

在实体类中添加与数据库对应的属性,并添加 @TableLogic 注解,使用 value 表示没有被删除时候的值,delval 表示被删除后的值。

在配置了 @TableLogic 注解后,MyBatis-Plus 会自动处理以下几种情况:

  • 查询:自动过滤掉 deleted = 1 的记录,除非你明确指定要查询被逻辑删除的数据。
  • 删除:执行删除操作时,并不会真正删除记录,而是将 deleted 字段设置为 1
  • 更新:更新操作也会自动过滤掉被逻辑删除的记录。

# 3 测试

下面测试一下删除。

通过用户名删除用户。

LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
// 1.设置查询条件
updateWrapper.eq(User::getUsername, "niubi");

// 2.执行删除操作
int result = userMapper.delete(updateWrapper);
log.info("执行结果:{}", result);
1
2
3
4
5
6
7

执行如下:

可以看到执行的是更新操作,更新了 deleted 字段的值,不是删除。

# 10.2 全局配置

逻辑删除还可以在全局配置。

# 1 全局配置

在 SpringBoot 项目的 application.yaml 中配置全局的逻辑删除。

# mybaits-plus配置
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted  # 逻辑删除字段名(对应数据库中的列名)
      logic-not-delete-value: 0  # 表示未删除的值
      logic-delete-value: 1  # 表示已删除的值
1
2
3
4
5
6
7

通过配置全局逻辑删除,那么实体类上的 deleted 属性只需要添加 @TableLogic 注解,不用写 (value="0",delval="1")

public class User {
    // ...其他属性,略
    
    @TableLogic
    private Integer deleted;
}
1
2
3
4
5
6

# 2 逻辑删除后的查询

被逻辑删除的数据,使用 QueryWrapper 进行查询的时候,是不会被查询出来的。

举个栗子,根据用户名来查询:

// 1.创建条件对象
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();

// 2.设置条件
queryWrapper.eq(User::getUsername, "niubi");

// 3.查询
User user = userMapper.selectOne(queryWrapper);
log.info("查询结果:{}", user);
1
2
3
4
5
6
7
8
9

执行的 SQL 如下:

SELECT id,username,password,age,email,create_time,update_time,deleted FROM tb_user WHERE deleted=0 AND (username = ?)
1

可以看到查询的时候会自动添加逻辑删除字段的过滤。


**但是需要注意,如果是自己在 Mapper 中定义的查询方法,是不会自动过滤的,需要自己手动过滤的。**这样是非常合理的,否则我们想查询被删除的数据都查询不到。