第一次接触逻辑删除这个概念时,我也是一头雾水。直到有次在项目中需要实现"回收站"功能,才真正理解它的价值。简单来说,逻辑删除就是在数据库中不真正删除数据,而是通过标记字段来标识数据是否被删除。比如电商平台的订单取消、社交媒体的帖子隐藏,这些场景都需要保留原始数据。
MyBatis-Plus的逻辑删除功能帮我们自动实现了这个机制。开启后,所有删除操作都会变成更新操作,查询时也会自动过滤已标记删除的数据。这比手动在每个SQL中添加条件要方便得多。我刚开始用的时候,最直观的感受就是代码变简洁了——不再需要到处写"WHERE deleted=0"这样的条件。
在实际项目中,我更推荐使用YAML配置方式。这种方式统一管理逻辑删除规则,团队协作时不会出现字段不统一的问题。配置示例如下:
yaml复制mybatis-plus:
global-config:
db-config:
logic-delete-field: is_delete # 逻辑删除字段名
logic-delete-value: 1 # 删除标记值
logic-not-delete-value: 0 # 未删除标记值
这里有个小技巧:字段名最好与数据库列名保持一致。比如数据库用"is_delete",实体类也用"isDelete"。我遇到过字段名不一致导致的问题,排查起来很费时间。
虽然不推荐,但在某些特殊场景下可能需要使用注解方式。比如要临时覆盖全局配置,或者处理遗留系统的特殊字段:
java复制@Data
public class User {
@TableLogic(value = "1", delval = "0")
private Integer isDeleted;
}
注意value和delval的值要与全局配置一致。我在一个老项目中就踩过坑:全局配置用1表示删除,但某个实体类注解用"Y"表示删除,结果导致逻辑混乱。
开启逻辑删除后,最明显的变化就是删除行为的改变。我们来看个例子:
java复制@Test
public void testDelete() {
userMapper.deleteById(1); // 实际执行的是UPDATE
}
这个简单的删除操作,实际执行的SQL是:
sql复制UPDATE user SET is_delete=1 WHERE id=1 AND is_delete=0
这里有个细节:MyBatis-Plus会自动添加"AND is_delete=0"条件。这意味着如果记录已经被逻辑删除,再次删除也不会报错。这个设计很贴心,避免了很多不必要的异常处理。
查询时,MyBatis-Plus会自动帮我们过滤已删除的数据:
java复制List<User> users = userMapper.selectList(null);
生成的SQL会包含"WHERE is_delete=0"条件。这个特性在开发后台管理系统时特别有用,我们不再需要手动处理数据过滤。
这是最常见的坑。比如我们写了个自定义查询:
java复制@Select("SELECT * FROM user ${ew.customSqlSegment}")
List<User> customQuery(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
执行这个查询时,逻辑删除条件不会自动添加。我遇到过好几次因为这个原因导致已删除数据被查出来的情况。
解决方案有两种:
java复制userMapper.customQuery(Wrappers.<User>query().eq("is_delete", 0));
xml复制<select id="customQuery">
SELECT * FROM user WHERE is_delete=0
</select>
有时候我们不需要查询逻辑删除字段,可以在实体类中这样配置:
java复制@TableField(select = false)
private Integer isDelete;
这样生成的SELECT语句就不会包含这个字段。但要注意,这不会影响WHERE条件的自动添加。
在连表查询时,逻辑删除条件可能只对主表生效。比如:
sql复制SELECT a.*, b.* FROM user a LEFT JOIN department b ON a.dept_id = b.id
这种情况下,department表的逻辑删除条件不会被自动添加。我的经验是,对于复杂查询最好使用XML方式明确写出所有条件。
经过多个项目的实践,我总结出以下几点经验:
统一命名规范:全项目使用相同的逻辑删除字段名和值。我习惯用"is_deleted"作为字段名,1表示删除,0表示正常。
谨慎使用自定义SQL:尽量使用MyBatis-Plus提供的标准方法。必须用自定义SQL时,记得手动处理逻辑删除条件。
测试要充分:特别是批量删除、连表查询等复杂场景。我曾经因为没测试批量删除,导致生产环境出现数据问题。
考虑数据恢复需求:提前规划好数据恢复的方案。可以开发一个管理员专用的恢复接口,但要注意权限控制。
性能优化:逻辑删除字段一定要加索引。我遇到过因为没加索引导致查询性能下降的情况。