Jooq实现软删除记录及无过滤条件查询软删除表的方案咨询
在jOOQ中实现透明软删除的最佳实践
这问题我之前在项目里也踩过坑,正好可以用jOOQ的内置机制搞定,不用每次手动写WHERE deleted=false,让软删除操作完全透明化!下面分享两种最常用的方案:
方案一:全局拦截器(VisitListener)实现自动过滤与操作替换
这是最通用的方案,通过jOOQ的VisitListener拦截SQL生成和执行过程,自动给查询加软删除过滤,同时把硬删除转成软删除更新。
1. 自定义软删除拦截器
public class SoftDeleteListener implements VisitListener { // 假设软删除字段统一命名为`deleted`,类型为Boolean private static final Field<Boolean> DELETED_FIELD = DSL.field("deleted", Boolean.class); @Override public void visitStart(VisitContext context) { // 处理查询:自动给SELECT语句添加软删除过滤 if (context.query() instanceof SelectQuery<?>) { SelectQuery<?> query = (SelectQuery<?>) context.query(); // 避免重复添加条件(比如手动加过的情况) if (!query.getConditions().stream().anyMatch(c -> c.toString().contains("deleted"))) { query.addConditions(DELETED_FIELD.eq(false)); } } // 处理删除:把DELETE操作替换成UPDATE设置deleted=true else if (context.query() instanceof DeleteQuery<?>) { DeleteQuery<?> deleteQuery = (DeleteQuery<?>) context.query(); UpdateQuery<?> updateQuery = context.configuration().dsl() .updateQuery(deleteQuery.getTable()); // 复制原删除的条件到更新语句 updateQuery.addConditions(deleteQuery.getConditions()); // 设置软删除标记 updateQuery.addValues(DELETED_FIELD, true); deleteQuery.cancel(); // 取消原删除操作 updateQuery.execute(); // 执行软删除更新 } } }
2. 注册拦截器到jOOQ配置
// 构建jOOQ配置时添加拦截器 Configuration config = new DefaultConfiguration() .set(SQLDialect.MYSQL) // 替换成你的数据库方言 .set(dataSource) .set(new DefaultVisitListenerProvider(new SoftDeleteListener())); DSLContext dsl = DSL.using(config);
这样配置后,你直接写dsl.selectFrom(USERS)就会自动生成SELECT * FROM users WHERE deleted=false,调用dsl.deleteFrom(USERS).where(USERS.ID.eq(1))则会执行UPDATE users SET deleted=true WHERE id=1。
方案二:代码生成器自定义表实现
如果需要更细粒度的控制(比如某些表不需要软删除),可以通过jOOQ代码生成器给指定表自动添加默认过滤条件。
1. 自定义表类生成器
public class SoftDeleteTableGenerator extends JavaGenerator { @Override protected void generateTableClassFooter(TableDefinition table, JavaWriter out) { // 只给包含`deleted`字段的表添加默认查询逻辑 if (table.getColumns().stream().anyMatch(c -> c.getName().equals("deleted"))) { out.println(); out.println(" // 自动添加软删除过滤的默认查询"); out.println(" @Override"); out.println(" public SelectConditionStep<Record> select() {"); out.println(" return super.select().where(deleted.eq(false));"); out.println(" }"); out.println(); out.println(" // 重写delete方法为软删除"); out.println(" public int delete(Configuration configuration, Condition condition) {"); out.println(" return DSL.using(configuration)"); out.println(" .update(this)"); out.println(" .set(deleted, true)"); out.println(" .where(condition)"); out.println(" .execute();"); out.println(" }"); } super.generateTableClassFooter(table, out); } }
2. 配置代码生成器
在maven/gradle的jOOQ生成器配置中指定自定义生成器:
<!-- Maven示例 --> <plugin> <groupId>org.jooq</groupId> <artifactId>jooq-codegen-maven</artifactId> <configuration> <generator> <name>com.yourpackage.SoftDeleteTableGenerator</name> <!-- 其他生成器配置(数据库连接、包名等) --> </generator> </configuration> </plugin>
生成后的表对象会自带过滤后的select()方法,调用USERS.select()就直接返回未删除的数据。
注意事项
- 如果需要查询包含已删除的数据,手动添加
deleted.isNotNull()或者DSL.trueCondition()覆盖默认条件即可; - 关联查询时,两种方案都会自动给关联表添加过滤(如果表有
deleted字段),如果不需要可以手动移除条件; - 批量操作和批量删除也会被拦截处理,测试时要注意验证SQL生成结果。
内容的提问来源于stack exchange,提问作者Boris
相关产品推荐
相关产品推荐

