关于逻辑删除配置,只要满足以下两个前提,MyBatis-Flex都会自动追加逻辑删除条件。
当然,并不是所有场景都能覆盖,需要有前置条件。
实体类已配置:对应的实体类属性标注了
@Column(isLogicDelete = true)使用 MyBatis-Flex 的标准 API 查询:如
Mapper.selectListByQuery、QueryWrapper
在使用 MyBatis-Flex 逻辑删除时,需要特别注意自动注入失效或需要特殊处理的场景。
不会启用逻辑删除的场景
1.自定义 XML 或 @Select 原生 SQL
如果在 .xml 映射文件中或者使用 @Select("SELECT * FROM user WHERE id = #{id}") 编写了原生 SQL,MyBatis-Flex 不会对 SQL 进行 AST 解析并自动追加 deleted = 0。
在这类手写 SQL 的场景下,必须手动写明 AND deleted = 0,框架不会自动帮你填写。
2.执行不带实体类型的 Db 查询
如果直接使用 Db.selectListBySql("select * from user") 这种不与实体 Class 绑定的方法,框架无法获取到实体的 @Column 注解信息。
因此,在使用 Db 工具类时,推荐使用带有实体 Class 泛型的方法。
例如 Db.selectListByQuery(QueryWrapper.create().from(User.class))。只要指定了实体类,逻辑删除依然会自动追加。
3.多表联查时的行为
在进行 leftJoin / innerJoin 等多表关联查询时,MyBatis-Flex 会自动在联查的 ON 条件或整个 WHERE 尾部,为主表和所有关联表自动追加其对应的 deleted = 0 约束。
需要注意,如果您在某些特定业务中,需要关联出已被删除的子表数据,必须在 QueryWrapper 中显式调用 QueryWrapper.noLogicDelete() 或者使用LogicDeleteManager.execWithoutLogicDelete(...)包裹语句来暂时停用自动追加行为
4.更新已被逻辑删除的数据
当执行 update 操作时,MyBatis-Flex 同样会自动在 WHERE 条件中注入 AND deleted = 0。等同于无法通过常规的 update 接口去修改一条已经被逻辑删除的数据。
4种忽略逻辑方式对比
| 方式 | 作用域 | 核心 API / 配置 | 适用场景 |
|---|---|---|---|
| 单次查询忽略 | 当前QueryWrapper | QueryWrapper.noLogicDelete() | 仅在某一次查询中需要包含已删除数据 |
| 线程上下文忽略 | 当前线程/代码块 | LogicDeleteManager.execWithoutLogicDelete(...) | 批量数据同步、后台管理大批物理/逻辑混合操作,免去在每个 Query 里加配置 |
| 实体类级别不启用 | 单张表/实体 | 移除 @Column(isLogicDelete = true) | 该表采用物理删除,或者不需要逻辑删除机制 |
| 全局配置关闭 | 整个应用 | 移除逻辑删除处理器 (LogicDeleteProcessor) | 全局重构,彻底弃用逻辑删除机制 |
详细方式及区别解析
1.单次查询忽略
通过在构建 QueryWrapper 时,显式调用 noLogicDelete() 方法,来指示当前查询不拼接 deleted = 0 的条件,忽略逻辑删除。
- 代码示例:
QueryWrapper queryWrapper = QueryWrapper.create()
.select()
.from(User.class)
.where(User::getId).eq(1L)
.noLogicDelete(); // 关键:关闭此查询的逻辑删除
User user = userMapper.selectOneByQuery(queryWrapper);
- 特点:
- 安全可控:仅对当前这一个
QueryWrapper生成的 SQL 生效,不会污染其他查询。 - 支持多表联查:如果有多表Join,调用
noLogicDelete()将同时使主表和关联表都忽略逻辑删除过滤,免于复杂 SQL 重复填写。
2.线程上下文忽略
此方式为
ThreadLocal级别。
MyBatis-Flex 提供了 LogicDeleteManager 工具类。它利用 ThreadLocal 机制,在指定的代码块内,使所有执行的数据库操作全部忽略逻辑删除过滤。
- 代码示例:
// 在这个 Lambda 代码块内部,执行的所有 Mapper 查询都会忽略逻辑删除
List<User> list = LogicDeleteManager.execWithoutLogicDelete(() -> {
return userMapper.selectAll();
});
- 特点:
- 免侵入:不需要修改任何
QueryWrapper的构造。 - 传播性:如果代码块内调用了其他 Service 的方法,那些方法内的查询也会同时忽略。
- 安全性:它是基于
ThreadLocal 的。MyBatis-Flex 会在执行完后自动清除 ThreadLocal 变量,因此不需要担心线程池复用导致的污染问题,设计非常安全。
特别注意:
在使用
LogicDeleteManager.execWithoutLogicDelete() 时,由于它是基于ThreadLocal 的,如果在代码块中新开了子线程,如使用@Async 或CompletableFuture,子线程中的查询仍然会有逻辑删除过滤。此时需要通过
noLogicDelete() 或在子线程内部再次使用LogicDeleteManager来解决。
3.实体类级别不启用
如果在设计表时,某张表根本不需要逻辑删除,指定其直接 delete 物理删除。
- 做法:
直接不在实体的属性上加@Column(isLogicDelete = true),或者将其设为默认的false,只要不填,逻辑删除便不启用。 - 特点:
- 调用
deleteById 时,底层执行的是真实的DELETE FROM table WHERE id = ?物理删除。 - 所有针对该表的
select 查询均不会拼接任何deleted的条件。
4.全局配置关闭
如果你在重构系统,想把整个项目的逻辑删除机制彻底停用。
- 做法:
- 如果使用的是 Spring Boot,不注入任何
IDialect 中关联的LogicDeleteProcessor。 - 或者直接将 MyBatis-Flex 的逻辑删除全局配置项
mybatis-flex.global-config.normal-value全部注销。 - 特点:
- 此时即便实体类上写了
@Column(isLogicDelete = true),框架也会因为找不到逻辑删除处理器而退化为正常的列,不再进行自动 SQL 注入。

Comments NOTHING