Jooq中的条件查询日志记录

时间:2017-06-12 15:08:27

标签: java sql jooq

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

这是我们目前的倾听者。

@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());
    }
}

1 个答案:

答案 0 :(得分:1)

强大的解决方案:RenderContext

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

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

强大的解决方案:VisitListener

jOOQ知道VisitListener SPI,它允许您挂钩渲染生命周期。这个SPI的想法是能够修改生成的SQL内容(e.g. to implement more sophisticated multi-tenancy or row level security features)。

在您的情况下,您不会操纵jOOQ表达式树,而只是收集正在渲染的所有表,并将它们存储在记录器可访问的某个位置。

此解决方案可能对渲染性能产生很小的影响。

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

为了完整性'为了清楚(因为我确定你自己已经想过这个),我列出了一个简单的解决方案,只有当某个正则表达式与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()内部。我不是在这里记录这个,因为它可能会发生变化,属于内部。

但为了完整性'值得一提的是,因为这可能是一个很好的解决方案。