Available in versions: Dev (3.19) | Latest (3.18) | 3.17 | 3.16 | 3.15 | 3.14 | 3.13 | 3.12 | 3.11 | 3.10 | 3.9
ExecuteListeners
Applies to ✅ Open Source Edition ✅ Express Edition ✅ Professional Edition ✅ Enterprise Edition
The Configuration lets you specify a list of org.jooq.ExecuteListener
instances. The ExecuteListener is essentially an event listener for Query, Routine, or ResultSet render, prepare, bind, execute, fetch steps. It is a base type for loggers, debuggers, profilers, data collectors, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.
For convenience and better backwards-compatibility, consider extending org.jooq.impl.DefaultExecuteListener
instead of implementing this interface.
Example: Query statistics ExecuteListener
Here is a sample implementation of an ExecuteListener, that is simply counting the number of queries per type that are being executed using jOOQ:
package com.example; // Extending DefaultExecuteListener, which provides empty implementations for all methods... public class StatisticsListener extends DefaultExecuteListener { /** * 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); } }
Now, configure jOOQ's runtime to load your listener
// 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);
And log results any time with a snippet like this:
log.info("STATISTICS"); log.info("----------"); for (ExecuteType type : ExecuteType.values()) { log.info(type.name(), StatisticsListener.STATISTICS.get(type) + " executions"); }
This may result in the following log output:
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
Please read the ExecuteListener Javadoc for more details
Example: Custom Logging ExecuteListener
The following depicts an example of a custom ExecuteListener, which pretty-prints all queries being executed by jOOQ to stdout:
import org.jooq.DSLContext; import org.jooq.ExecuteContext; import org.jooq.conf.Settings; import org.jooq.impl.DefaultExecuteListener; import org.jooq.tools.StringUtils; public class PrettyPrinter extends DefaultExecuteListener { /** * 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())); } } }
See also the manual's sections about logging for more sample implementations of actual ExecuteListeners.
Example: Bad query execution ExecuteListener
You can also use ExecuteListeners to interact with your SQL statements, for instance when you want to check if executed UPDATE
or DELETE
statements contain a WHERE
clause. This can be achieved trivially with the following sample ExecuteListener:
public class DeleteOrUpdateWithoutWhereListener extends DefaultExecuteListener { @Override public void renderEnd(ExecuteContext ctx) { if (ctx.sql().matches("^(?i:(UPDATE|DELETE)(?!.* WHERE ).*)$")) { throw new DeleteOrUpdateWithoutWhereException(); } } } public class DeleteOrUpdateWithoutWhereException extends RuntimeException {}
You might want to replace the above implementation with a more efficient and more reliable one, of course.
Feedback
Do you have any feedback about this page? We'd love to hear it!