Jooq 中的条件查询日志记录

Conditional query logging in Jooq

我们有一个用于记录数据库查询的自定义执行侦听器,我们如何过滤掉仅针对某些 table 名称记录的查询? 目前每个执行的查询都会被记录下来。

这是我们当前的监听器。

@Override
public void executeStart(ExecuteContext ctx) {
    // Create a new DSLContext for logging rendering purposes
    // This DSLContext doesn't need a connection, only the SQLDialect...
    Settings setting = new Settings();
    setting.withRenderFormatted(true);
    setting.setExecuteLogging(true);
    StringBuilder message = new StringBuilder();
    DSLContext create = DSL.using(ctx.configuration().dialect(),
            // ... and the flag for pretty-printing
            new Settings().withRenderFormatted(true));
    // If we're executing a query
    if (ctx.query() != null && ENABLE_LOGGING) {
        LOGGER.debug(message.append(DynamicApplicationConfig.getStringProperty("API_ENV","dev"))
                .append(" - ")
                .append(create.renderInlined(ctx.query())).toString());
    }
    // If we're executing a routine
    else if (ctx.routine() != null && ENABLE_LOGGING) {
        LOGGER.debug(message.append(DynamicApplicationConfig.getStringProperty("API_ENV","dev"))
                .append(" - ")
                .append(create.renderInlined(ctx.routine())).toString());
    }
    // If we're executing anything else (e.g. plain SQL)
    else if (!StringUtils.isBlank(ctx.sql()) && ENABLE_LOGGING) {
        LOGGER.debug(message.append(DynamicApplicationConfig.getStringProperty("API_ENV","dev"))
                .append(" - ")
                .append(ctx.sql()).toString());
    }
}

稳健的解决方案:RenderContext

jOOQ 查询通过 RenderContext API 生成一个 SQL 字符串,这是一个 API 传递给每个 jOOQ QueryPart 以便生成 SQL 字符串内容和绑定变量。您可以自己实现并通过查询传递它,以便收集查询中包含的所有 table。

请注意,RenderContext API 可能会在以后的次要版本中接收新方法,因此此实现可能会在不同版本之间中断。

稳健的解决方案:VisitListener

jOOQ 知道 VisitListener SPI, which allows you to hook into the rendering lifecycle. The idea of this SPI is to be able to modify the generated SQL content (e.g. to implement more sophisticated multi-tenancy or row level security features).

在您的情况下,您不会操作 jOOQ 表达式树,而只是收集所有正在呈现的 tables,并将它们存储在记录器可访问的某个地方。

此解决方案可能会对渲染性能产生轻微影响。

快速而肮脏的解决方案:正则表达式

为了完整起见(我相信你自己已经想到了这一点),我列出了一个简单的解决方案,只有当某个正则表达式匹配 SQL 字符串时才会记录消息,例如:

if (ctx.query() != null && ENABLE_LOGGING 
                        && ctx.sql().matches("(?i:.*?\bmy_table_name\b.*)") {
    LOGGER.debug(message.append(
             DynamicApplicationConfig.getStringProperty("API_ENV","dev"))
          .append(" - ")
          .append(create.renderInlined(ctx.query())).toString());
}

当然,您的实际正则表达式可能更复杂

快速而肮脏的解决方案:使用反射访问内部结构

当然,您可以尝试访问 ctx.query() 的内部结构,其中存储了 table 引用。我没有在这里记录这个,因为它可能会发生变化,是内部的。

但为了完整起见,值得一提,因为对于您的情况,这可能是一个足够好的解决方案。