Available in versions: Dev (3.21) | Latest (3.20) | 3.19 | 3.18 | 3.17 | 3.16 | 3.15 | 3.14 | 3.13 | 3.12 | 3.11

ExecuteListeners

适用于 ✅ 开源版   ✅ 专业版   ✅ 企业版

通过 Configuration,您可以指定一个 org.jooq.ExecuteListener 实例列表。ExecuteListener 本质上是 Query、Routine 或 ResultSet 渲染、准备、绑定、执行、获取步骤的事件侦听器。它是日志记录器、调试器、分析器、数据收集器、触发器等的基础类型。高级 ExecuteListener 还可以在适当的方法中为 jOOQ 提供 Connection、PreparedStatement 和 ResultSet 的自定义实现。

示例:查询统计 ExecuteListener

这是一个 ExecuteListener 的示例实现,它只是统计使用 jOOQ 执行的每种类型的查询数量。

package com.example;

public class StatisticsListener implements ExecuteListener {

    /**
     * Generated UID
     */
    private static final long                     serialVersionUID = 7399239846062763212L;

    public static final Map<ExecuteType, Integer> STATISTICS       = new ConcurrentHashMap<>();

    @Override
    public void start(ExecuteContext ctx) {
        STATISTICS.compute(ctx.type(), (k, v) -> v == null ? 1 : v + 1);
    }
}

现在,配置 jOOQ 的运行时以加载您的侦听器。

// Create a configuration with an appropriate listener provider:
Configuration configuration = new DefaultConfiguration().set(connection).set(dialect);
configuration.set(new DefaultExecuteListenerProvider(new StatisticsListener()));

// Create a DSLContext from the above configuration
DSLContext create = DSL.using(configuration);

并随时使用类似这样的代码段记录结果

log.info("STATISTICS");
log.info("----------");

for (ExecuteType type : ExecuteType.values()) {
    log.info(type.name(), StatisticsListener.STATISTICS.get(type) + " executions");
}

这可能会导致以下日志输出

15:16:52,982  INFO - TEST STATISTICS
15:16:52,982  INFO - ---------------
15:16:52,983  INFO - READ                     : 919 executions
15:16:52,983  INFO - WRITE                    : 117 executions
15:16:52,983  INFO - DDL                      : 2 executions
15:16:52,983  INFO - BATCH                    : 4 executions
15:16:52,983  INFO - ROUTINE                  : 21 executions
15:16:52,983  INFO - OTHER                    : 30 executions

请阅读 ExecuteListener Javadoc 以获取更多详细信息

示例:自定义日志记录 ExecuteListener

以下描述了一个自定义 ExecuteListener 的示例,它将 jOOQ 执行的所有查询以漂亮的格式打印到 stdout

import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.conf.Settings;
import org.jooq.tools.StringUtils;

public class PrettyPrinter implements ExecuteListener {

    /**
     * Hook into the query execution lifecycle before executing queries
     */
    @Override
    public void executeStart(ExecuteContext ctx) {

        // Create a new DSLContext for logging rendering purposes
        // This DSLContext doesn't need a connection, only the SQLDialect...
        DSLContext create = DSL.using(ctx.dialect(),

        // ... and the flag for pretty-printing
            new Settings().withRenderFormatted(true));

        // If we're executing a query
        if (ctx.query() != null) {
            System.out.println(create.renderInlined(ctx.query()));
        }

        // If we're executing a routine
        else if (ctx.routine() != null) {
            System.out.println(create.renderInlined(ctx.routine()));
        }
    }
}

另请参阅手册中关于 日志记录的部分,以获取实际 ExecuteListener 的更多示例实现。

示例:错误的查询执行 ExecuteListener

您还可以使用 ExecuteListeners 与您的 SQL 语句进行交互,例如,当您想检查执行的 UPDATEDELETE 语句是否包含 WHERE 子句时。这可以使用以下示例 ExecuteListener 轻松实现

public class DeleteOrUpdateWithoutWhereListener implements ExecuteListener {

    @Override
    public void renderEnd(ExecuteContext ctx) {
        if (ctx.sql().matches("^(?i:(UPDATE|DELETE)(?!.* WHERE ).*)$")) {
            throw new DeleteOrUpdateWithoutWhereException();
        }
    }
}

public class DeleteOrUpdateWithoutWhereException extends RuntimeException {}

当然,您可能希望用更有效和更可靠的实现来替换上述实现。

反馈

您对此页面有任何反馈吗? 我们很乐意听到您的声音!

The jOOQ Logo