You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:29:39