文章目录
- 前言
- 一、逻辑删除的工作原理
- 二、支持的数据类型
- 三、使用方法
-
- 1.配置全局逻辑删除属性
- [2.在实体类中使用 @TableLogic 注解](#2.在实体类中使用 @TableLogic 注解)
- 四、常见问题解答
- [1. 如何处理插入操作?](#1. 如何处理插入操作?)
-
- [2. 删除接口自动填充功能失效怎么办?](#2. 删除接口自动填充功能失效怎么办?)
- 五、实战
-
- [1. 全局配置](#1. 全局配置)
- [2. 添加@TableLogic](#2. 添加@TableLogic)
- [3. 自动填充](#3. 自动填充)
- [4. 增删改查](#4. 增删改查)
- [5. 结果](#5. 结果)
- 总结
前言
逻辑删除是一种优雅的数据管理策略,它通过在数据库中标记记录为"已删除"而非物理删除,来保留数据的历史痕迹,同时确保查询结果的整洁性。MyBatis-Plus 提供了便捷的逻辑删除支持,使得这一策略的实施变得简单高效。
一、逻辑删除的工作原理
MyBatis-Plus 的逻辑删除功能会在执行数据库操作时自动处理逻辑删除字段。以下是它的工作方式:
- 插入:逻辑删除字段的值不受限制。
- 查找:自动添加条件,过滤掉标记为已删除的记录。
- 更新:防止更新已删除的记录。
- 删除:将删除操作转换为更新操作,标记记录为已删除。
例如:
- 删除:update user set deleted=1 where id = 1 and deleted=0
- 查找:select id,name,deleted from user where deleted=0
二、支持的数据类型
逻辑删除字段支持所有数据类型,但推荐使用 Integer
、Boolean
或 LocalDateTime
。如果使用 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 中实现逻辑删除功能,提高数据管理的灵活性和安全性。