MyBatis-Plus 处理逻辑删除与查询的5种核心实现方法
逻辑删除是实际开发中常用的数据保护策略,它通过在数据表中增加一个状态字段(如is_deleted、deleted)来标记数据是否被删除,而不是真正从数据库中物理删除记录。MyBatis-Plus 提供了完善且灵活的逻辑删除支持,本教程将详细介绍5种核心实现方法。
一、全局配置方法(推荐)
这是最常用且最便捷的方式,通过配置文件一次性设置所有逻辑删除规则。
核心配置代码:
# application.yml
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段名
logic-delete-value: 1 # 逻辑已删除值(默认为1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为0)讲解要点:
logic-delete-field:指定逻辑删除字段名,所有实体类都会使用这个字段logic-delete-value:删除时设置的值,通常为1或truelogic-not-delete-value:未删除时的值,通常为0或false- 配置后,所有继承
BaseMapper的Mapper都会自动应用此逻辑 - 删除操作会变为UPDATE语句,查询会自动添加
deleted=0条件
优势: 配置简单,一劳永逸,适合项目统一规范。
二、实体类注解配置方法
当不同表使用不同的逻辑删除字段或值时,可以使用注解方式为每个实体类单独配置。
核心代码示例:
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
@Data
@TableName("user")
public class User {
private Long id;
private String name;
@TableLogic(value = "0", delval = "1")
private Integer deleted;
}
@Data
@TableName("product")
public class Product {
private Long id;
private String productName;
@TableLogic(value = "false", delval = "true")
private Boolean isDeleted;
}讲解要点:
@TableLogic注解标注在逻辑删除字段上value属性:未删除时的值,默认为"0"delval属性:删除后的值,默认为"1"- 支持多种数据类型:Integer、Boolean、String等
- 注解优先级高于全局配置,实现不同表的差异化配置
使用场景: 老项目改造、多数据库表结构不一致、特殊业务需求。
三、局部配置与自定义Wrapper方法
在某些特殊场景下,可能需要临时改变逻辑删除的行为,可以通过自定义Wrapper实现。
核心代码示例:
// 1. 查询时忽略逻辑删除条件
List<User> users = userMapper.selectList(
Wrappers.<User>lambdaQuery()
.apply("deleted = 1 or deleted = 0") // 自定义条件覆盖自动添加的条件
);
// 2. 使用自定义SQL完全控制
@Select("SELECT * FROM user WHERE id = #{id}")
User selectByIdIgnoreLogic(@Param("id") Long id);
// 3. 链式调用中的特殊处理
userMapper.selectList(
new QueryWrapper<User>()
.eq("status", 1)
.and(wrapper -> wrapper.eq("deleted", 0).or().isNull("deleted"))
);讲解要点:
apply()方法可以添加原生SQL片段,覆盖自动生成的逻辑删除条件- 自定义SQL注解(@Select、@Update等)不会自动添加逻辑删除条件
- 可以通过Wrapper手动构建包含逻辑删除条件的复杂查询
- 使用
or()和and()组合条件实现灵活控制
适用场景: 回收站功能、数据恢复、管理员查看所有数据。
四、查询自动过滤的深度控制
MyBatis-Plus默认自动过滤已删除数据,但我们可以通过多种方式控制这一行为。
核心配置与代码:
// 1. 配置类中自定义逻辑删除处理器
@Configuration
public class MybatisPlusConfig {
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector() {
@Override
protected String getLogicDeleteSql(TableInfo tableInfo, boolean withWhere) {
// 自定义逻辑删除SQL生成逻辑
String logicDeleteField = tableInfo.getLogicDeleteField();
return "UPDATE " + tableInfo.getTableName() +
" SET " + logicDeleteField + " = #{et." + logicDeleteField + "}" +
(withWhere ? " WHERE " + tableInfo.getKeyColumn() + "=#{et." + tableInfo.getKeyProperty() + "}" : "");
}
};
}
}
// 2. 使用@SqlParser注解控制过滤
@SqlParser(filter = true) // 过滤逻辑删除数据
public List<User> selectActiveUsers();
@SqlParser(filter = false) // 不过滤逻辑删除数据
public List<User> selectAllUsers();讲解要点:
- 可以自定义
LogicSqlInjector来改变SQL生成逻辑 @SqlParser注解的filter属性控制是否过滤逻辑删除数据- 支持在Service层、Mapper层或具体方法上使用
- 可以通过AOP或拦截器实现更复杂的过滤逻辑
五、多租户与逻辑删除的联合应用
在企业级应用中,逻辑删除常与多租户数据隔离结合使用。
核心代码示例:
// 1. 多租户配置类
@Configuration
public class TenantConfig {
@Bean
public TenantLineHandler tenantLineHandler() {
return new TenantLineHandler() {
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public Expression getTenantId() {
return new LongValue(UserContext.getCurrentTenantId());
}
@Override
public boolean ignoreTable(String tableName) {
// 忽略不需要多租户的表
return "system_config".equals(tableName);
}
};
}
}
// 2. 实体类同时支持多租户和逻辑删除
@Data
@TableName("order")
public class Order {
private Long id;
private String orderNo;
@TableField(fill = FieldFill.INSERT) // 自动填充租户ID
private Long tenantId;
@TableLogic
private Integer deleted;
}
// 3. 查询时自动添加租户和逻辑删除条件
List<Order> orders = orderMapper.selectList(
Wrappers.<Order>lambdaQuery()
.eq(Order::getStatus, 1)
// 会自动添加:AND tenant_id = 当前租户ID AND deleted = 0
);讲解要点:
- 多租户和逻辑删除可以无缝结合使用
- 查询时会自动添加
tenant_id = ? AND deleted = 0条件 - 删除操作会同时考虑租户隔离
- 通过
ignoreTable方法可以排除不需要多租户的表
注意事项与最佳实践
- 索引优化:逻辑删除字段建议添加索引,特别是数据量大的表
- 字段类型选择:
- 使用
tinyint或boolean类型,占用空间小 - 避免使用字符串类型,影响查询性能
- 使用
数据一致性:
// 事务中处理逻辑删除
@Transactional
public void deleteUserWithRelatedData(Long userId) {
// 删除用户
userMapper.deleteById(userId);
// 同时处理关联数据
userRoleMapper.deleteByUserId(userId);
// 记录操作日志
logService.saveDeleteLog(userId);
}- 查询性能:定期归档已删除数据,避免表数据量过大
- 兼容性考虑:老数据迁移时,需要批量更新逻辑删除字段
总结
MyBatis-Plus的逻辑删除功能设计巧妙且灵活,通过5种不同的实现方法,可以满足从简单到复杂的各种业务场景:
- 全局配置:适合项目统一规范,配置简单
- 注解配置:支持差异化配置,灵活性强
- 局部控制:满足特殊业务需求,可控性高
- 深度定制:支持SQL级别控制,扩展性好
- 多租户集成:适合企业级应用,安全性强
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 默认自动过滤 | 常规业务查询 | 自动生效,无需额外配置 | 无法查询已删除数据 |
| @InterceptorIgnore | 特殊场景查询已删除 | 灵活控制单次查询 | 需要写注解或自定义SQL |
| 条件构造器 | 复杂条件查询 | 可精确控制删除状态 | 需要手动添加条件 |
| 自定义SQL | 完全自定义需求 | 灵活性最高 | 维护成本较高 |
| SQL注入器 | 框架扩展需求 | 可复用性强 | 实现复杂度高 |
在实际开发中,建议根据项目规模和复杂度选择合适的方案。小型项目可以使用全局配置,大型复杂项目可以结合多种方式实现更精细的控制。逻辑删除不仅能保护数据安全,还能为数据恢复、审计追踪等功能提供支持,是现代应用开发中不可或缺的重要特性。
到此这篇关于MyBatis-Plus 处理逻辑删除与查询的5种核心实现方法的文章就介绍到这了,更多相关mybatisplus逻辑删除与查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
JavaEE中用response向客户端输出中文数据乱码问题分析
这篇文章主要介绍了JavaEE中用response向客户端输出中文数据乱码问题分析,需要的朋友可以参考下2014-10-10
Java实现的两种常见简单查找算法示例【快速查找与二分查找】
这篇文章主要介绍了Java实现的两种常见简单查找算法,结合具体实例形式分析了java快速查找与二分查找的原理与简单实现技巧,需要的朋友可以参考下2017-09-09


最新评论