【第20章】MyBatis-Plus逻辑删除支持

文章目录


前言

逻辑删除是一种优雅的数据管理策略,它通过在数据库中标记记录为"已删除"而非物理删除,来保留数据的历史痕迹,同时确保查询结果的整洁性。MyBatis-Plus 提供了便捷的逻辑删除支持,使得这一策略的实施变得简单高效。


一、逻辑删除的工作原理

MyBatis-Plus 的逻辑删除功能会在执行数据库操作时自动处理逻辑删除字段。以下是它的工作方式:

  • 插入:逻辑删除字段的值不受限制。
  • 查找:自动添加条件,过滤掉标记为已删除的记录。
  • 更新:防止更新已删除的记录。
  • 删除:将删除操作转换为更新操作,标记记录为已删除。

例如:

  • 删除:update user set deleted=1 where id = 1 and deleted=0
  • 查找:select id,name,deleted from user where deleted=0

二、支持的数据类型

逻辑删除字段支持所有数据类型,但推荐使用 IntegerBooleanLocalDateTime。如果使用 datetime 类型,可以配置逻辑未删除值为 null,已删除值可以使用函数如 now() 来获取当前时间。

三、使用方法

1.配置全局逻辑删除属性

application.yml 中配置 MyBatis-Plus 的全局逻辑删除属性:

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

2.在实体类中使用 @TableLogic 注解

在实体类中,对应数据库表的逻辑删除字段上添加 @TableLogic 注解:

yml 复制代码
import com.baomidou.mybatisplus.annotation.TableLogic;

public class User {
    // 其他字段...

    @TableLogic
    private Integer deleted;
}

四、常见问题解答

注意事项

  • 逻辑删除的本质:逻辑删除的效果应等同于物理删除,其目的是为了保留数据,实现数据价值最大化。
  • 业务需求考量:如果业务中仍需频繁查询这些"已删除"的数据,应考虑是否真正需要逻辑删除。或许,一个状态字段来控制数据的可见性更为合适。

1. 如何处理插入操作?

  • 方法一:在数据库中为逻辑删除字段设置默认值。
  • 方法二:在插入数据前手动设置逻辑删除字段的值。
  • 方法三:使用 MyBatis-Plus 的自动填充功能。

2. 删除接口自动填充功能失效怎么办?

  • 方法一:使用 deleteById 方法。
  • 方法二:使用 update 方法,并使用 UpdateWrapper.set(column, value)。
  • 方法三:使用 update 方法,并使用 UpdateWrapper.setSql("column=value")。
  • 方法四:使用 Sql 注入器注入 com.baomidou.mybatisplus.extension.injector.methods.LogicDeleteByIdWithFill 并使用(3.5.0版本已废弃,推荐使用deleteById)。

五、实战

1. 全局配置

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

2. 添加@TableLogic

html 复制代码
package org.example.springboot3.mybatisplus.model;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.example.springboot3.mybatisplus.enums.GenderEnum;
import org.example.springboot3.mybatisplus.enums.StatusEnum;
import java.time.LocalDateTime;

/**
 * Create by zjg on 2024/6/27
 */
@Getter
@Setter
@ToString
@TableName("user1")
@NoArgsConstructor
public class User {
    @TableId(type= IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private GenderEnum gender;
    private StatusEnum status;
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
    @TableLogic
    @TableField(fill = FieldFill.INSERT)
    private Integer deleted;

    public User(String name) {
        this.name = name;
    }

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public User(String name, int age) {
        this.name=name;
        this.age=age;
    }
    public User(long id, String name, int age) {
        this.id=id;
        this.name=name;
        this.age=age;
    }
}

3. 自动填充

这里插入数据的时候,我们选择前面刚学习过的自动填充

java 复制代码
package org.example.springboot3.mybatisplus.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

/**
 * Create by zjg on 2024/7/2
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Value("${mybatis-plus.global-config.db-config.logic-not-delete-value}")
    private Integer deleted;
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入填充...");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "deleted", Integer.class, deleted);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始更新填充...");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

4. 增删改查

java 复制代码
package org.example.springboot3.mybatisplus.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.example.springboot3.mybatisplus.model.User;
import org.example.springboot3.mybatisplus.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

/**
 * Create by zjg on 2024/7/3
 */
@RestController
@RequestMapping("/table-logic/")
public class TableLogicController {
    @Autowired
    UserService userService;
    @RequestMapping("save")
    public void save() {
        // 假设有一个 User 实体对象
        User user = new User();
        user.setName("John Doe");
        user.setEmail("john.doe@example.com");
        boolean result = userService.save(user); // 调用 save 方法
        if (result) {
            System.out.println("User saved successfully.");
        } else {
            System.out.println("Failed to save user.");
        }
    }
    @RequestMapping("list")
    public void list() {
        // 查询所有用户
        List<User> users = userService.list(); // 调用 list 方法
        for (User user : users) {
            System.out.println("User: " + user);
        }
    }
    @RequestMapping("update")
    public void update() {
        // 假设有一个 UpdateWrapper 对象,设置更新条件为 name = 'John Doe',更新字段为 email
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("name", "John Doe").set("email", "john.doe@newdomain.com");
        boolean result = userService.update(updateWrapper); // 调用 update 方法
        if (result) {
            System.out.println("Record updated successfully.");
        } else {
            System.out.println("Failed to update record.");
        }
    }
    @RequestMapping("remove")
    public void remove() {
        // 假设有一个 QueryWrapper 对象,设置删除条件为 name = 'John Doe'
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", "John Doe");
        boolean result = userService.remove(queryWrapper); // 调用 remove 方法
        if (result) {
            System.out.println("Record deleted successfully.");
        } else {
            System.out.println("Failed to delete record.");
        }
    }
}

5. 结果

sql 复制代码
INSERT INTO user1 ( name, email, create_time, deleted ) VALUES ( ?, ?, ?, ? )
SELECT id,name,age,email,gender,status,create_time,update_time,deleted FROM user1 WHERE deleted=0
UPDATE user1 SET email=? WHERE deleted=0 AND (name = ?)
UPDATE user1 SET deleted=1 WHERE deleted=0 AND (name = ?)

总结

回到顶部

通过以上步骤,你可以轻松地在 MyBatis-Plus 中实现逻辑删除功能,提高数据管理的灵活性和安全性。

相关推荐
qq_433099408 分钟前
Ubuntu20.04从零安装IsaacSim/IsaacLab
数据库
Dlwyz10 分钟前
redis-击穿、穿透、雪崩
数据库·redis·缓存
Theodore_10221 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
工业甲酰苯胺2 小时前
Redis性能优化的18招
数据库·redis·性能优化
冰帝海岸2 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象3 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了3 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
jokerest1233 小时前
web——sqliabs靶场——第十三关——报错注入+布尔盲注
mybatis
小二·3 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端