Appearance
MyBatis-Plus 逻辑删除
逻辑删除(软删除)是指删除数据时,不真正删除数据库记录,而是通过标记字段将数据设置为"已删除"状态。MyBatis-Plus 通过 @TableLogic 注解一行搞定。
一、为什么需要逻辑删除?
物理删除 vs 逻辑删除:
物理删除:DELETE FROM user WHERE id = 1
优点:彻底删除,节省空间
缺点:数据不可恢复,审计困难,关联数据可能丢失
逻辑删除:UPDATE user SET deleted = 1 WHERE id = 1
优点:数据可恢复,保留审计记录,关联数据安全
缺点:占用空间,查询需额外过滤条件二、配置方式
2.1 全局配置
yaml
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除字段名
logic-delete-value: 1 # 已删除值
logic-not-delete-value: 0 # 未删除值2.2 实体类注解
java
@Data
@TableName("user")
public class User {
private Long id;
private String name;
@TableLogic
private Integer deleted; // 0=未删除,1=已删除
}三、使用效果
3.1 删除操作
java
// 调用 deleteById 自动变成 UPDATE
userMapper.deleteById(1L);
// 执行 SQL:UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0
// 批量删除
userMapper.deleteBatchIds(Arrays.asList(1L, 2L, 3L));
// UPDATE user SET deleted = 1 WHERE id IN (1,2,3) AND deleted = 0
// 条件删除
userMapper.delete(new LambdaQueryWrapper<User>().gt(User::getAge, 50));
// UPDATE user SET deleted = 1 WHERE age > 50 AND deleted = 03.2 查询操作
java
// 所有查询自动加上 deleted = 0
userMapper.selectById(1L);
// SELECT * FROM user WHERE id = 1 AND deleted = 0
userMapper.selectList(null);
// SELECT * FROM user WHERE deleted = 0
userMapper.selectList(
new LambdaQueryWrapper<User>().gt(User::getAge, 20)
);
// SELECT * FROM user WHERE age > 20 AND deleted = 03.3 更新操作
java
// 更新也自动过滤已删除数据
User user = new User();
user.setId(1L);
user.setAge(30);
userMapper.updateById(user);
// UPDATE user SET age = 30 WHERE id = 1 AND deleted = 0四、查询已删除数据
java
// 如果确实需要查询已删除的数据,需要手动忽略逻辑删除
// 方式一:在 XML 中直接写 SQL
@Select("SELECT * FROM user WHERE deleted = 1")
List<User> selectDeleted();
// 方式二:使用 @SqlParser 注解(3.5.1+)
@InterceptorIgnore(tenantLine = "true")
List<User> selectAll();五、逻辑删除原理
MyBatis-Plus 逻辑删除原理:
① 解析实体类 @TableLogic 注解
→ 获取逻辑删除字段名、已删除值、未删除值
② 拦截 SQL 执行
→ 通过 SqlSource 装饰器修改 SQL
③ DELETE 操作 → 改写为 UPDATE
→ DELETE FROM user WHERE id = 1
→ UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0
④ SELECT/UPDATE 操作 → 追加过滤条件
→ SELECT * FROM user WHERE age > 20
→ SELECT * FROM user WHERE age > 20 AND deleted = 0六、注意事项
① 逻辑删除字段建议加索引
CREATE INDEX idx_deleted ON user(deleted);
② 唯一索引注意
如果 name 有唯一索引,逻辑删除后同名用户无法再次创建
解决方法:使用联合唯一索引 (name, deleted)
③ 逻辑删除不支持级联
删除主表时,子表不会自动逻辑删除,需要手动处理
④ 数据迁移
逻辑删除的数据在迁移时需要特殊处理,建议定期归档
⑤ 物理删除怎么办?
如果确实需要物理删除,写原生 SQL 或自定义 Mapper七、速记总结
逻辑删除三步走:
① 数据库加字段:deleted TINYINT DEFAULT 0
② 实体类加注解:@TableLogic
③ 全局配置:logic-delete-value / logic-not-delete-value
效果:
DELETE → UPDATE SET deleted = 1
SELECT → 自动追加 AND deleted = 0
速记口诀:
逻辑删除注解标,删改变更查追加,
数据不丢可恢复,唯一索引要联合。八、面试要点
| 问题 | 答案要点 |
|---|---|
| 逻辑删除怎么实现? | @TableLogic 注解,DELETE 变 UPDATE,SELECT 追加过滤 |
| 逻辑删除字段建议? | 添加索引,唯一索引改成联合索引 |
| 如何查询已删除数据? | 写原生 SQL 或自定义 Mapper |
