JOOQ 侦听器:两个查询之间未清除上下文数据

JOOQ listeners: context data is not cleaned between two queries

在我目前的项目中,我使用java11/JOOQ 3.15/Micronaut/Micrometer。为了获得相关的 SQL 指标,我想在我的 JOOQ 查询中添加一个名称。

为此,我尝试将 ctx.data() 字段与自定义 ExecuteListener 结合使用。

让我们来看一个真正简化的监听器:

@Singleton
public class JooqListener extends DefaultExecuteListener {

    transient StopWatch watch;
    private final MeterRegistry meterRegistry;

    public JooqListener(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @Override
    public void executeStart(ExecuteContext ctx) {
        watch = new StopWatch();
    }

    @Override
    public void fetchEnd(ExecuteContext ctx) {
        Tags prometheusTag = Tags.of("queryName", ctx.configuration().data("queryName").toString());
        meterRegistry.timer("sql.query.timer", prometheusTag)
            .record(watch.split(), TimeUnit.NANOSECONDS);
    }
    // I have tried to remove the data manually, but not working
    @Override
    public void end(ExecuteContext ctx) {
        ctx.configuration().data().remove("queryName");
    }
}

如果我从两个不同的存储库发送 2 个不同的查询,例如:

DSLContext context = DSL.using(jooqConfiguration);
context.data("queryName", "query1");
return context.select(1).from("dual").fetch();

然后,假设我不专心,忘记命名我的查询:

DSLContext context = DSL.using(jooqConfiguration);
return context.select(2).from("dual").fetch();

ctx.configuration().data("queryName") 在我的侦听器中将始终包含“query1”,这是我没想到的,因为ExecuteListeners 正在逐个查询地侦听,而且我创建了两个不同的DSLContext。看起来 ctx.data() 无法清除,只能被覆盖。

这是预期的行为吗?我应该使用其他可以限制在查询范围内的 object/method 吗? (我在 google 上搜索了很多,但“数据”关键字有点烦人...)

谢谢

一个DSLContext只是包裹了一个Configuration。它没有自己的生命周期。因此,如果您通过 DSLContext 修改 Configuration.data() 映射,您就是在修改全局共享对象。换句话说,你不能修改 Configuration.data() 除了你第一次初始化你的配置。 See this section of the manual for more details.

完成您打算做的事情的更好方法是:

// Create a "derived" configuration, which is a new, 
// independent Configuration instance
DSLContext context = DSL.using(jooqConfiguration.derive());
context.data("queryName", "query1");
return context.select(1).from("dual").fetch();

然后,在你的 ExecuteListener:

@Override
public void fetchEnd(ExecuteContext ctx) {
    // Reading the Configuration.data() is still fine:
    Tags prometheusTag = Tags.of("queryName", 
        ctx.configuration().data("queryName").toString());
    meterRegistry.timer("sql.query.timer", prometheusTag)
        .record(watch.split(), TimeUnit.NANOSECONDS);
}

@Override
public void end(ExecuteContext ctx) {
    // But you shouldn't modify it
    ctx.configuration().data().remove("queryName");
}