JDBC Type 4 driver for MySQL with X DevAPI support for document store operations
Query and connection lifecycle interceptors for customizing driver behavior. Interceptors allow you to hook into query execution and connection events.
Interface for intercepting query execution.
package com.mysql.cj.interceptors;
public interface QueryInterceptor {
// Initialize interceptor
QueryInterceptor init(MysqlConnection conn, Properties props, Log log);
// Pre-process query (before execution)
<T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery);
// Check if should execute only at top level
boolean executeTopLevelOnly();
// Destroy interceptor
void destroy();
// Post-process query (after execution)
<T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
T originalResultSet, ServerSession serverSession);
}Usage:
// Implement custom query interceptor
public class MyQueryInterceptor implements QueryInterceptor {
private Log log;
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
this.log = log;
return this;
}
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery) {
log.logInfo("Executing query: " + sql.get());
return null; // null means proceed with execution
}
public boolean executeTopLevelOnly() {
return false; // Also intercept nested queries
}
public void destroy() {
// Cleanup
}
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
T originalResultSet, ServerSession serverSession) {
log.logInfo("Query completed: " + sql.get());
return originalResultSet;
}
}
// Configure interceptor in URL
String url = "jdbc:mysql://localhost:3306/mydb" +
"?queryInterceptors=com.mycompany.MyQueryInterceptor";
Connection conn = DriverManager.getConnection(url, "user", "pass");
// All queries will be intercepted
Statement stmt = conn.createStatement();
stmt.executeQuery("SELECT * FROM users");Interface for intercepting connection lifecycle events.
package com.mysql.cj.jdbc.interceptors;
public interface ConnectionLifecycleInterceptor {
// Initialize interceptor
ConnectionLifecycleInterceptor init(MysqlConnection conn, Properties props, Log log);
// Destroy interceptor
void destroy();
// Called when new session is created
void createNewSession();
// Called when transaction begins
void transactionBegun();
// Called when transaction completes (commit or rollback)
void transactionCompleted();
}Usage:
// Implement custom connection lifecycle interceptor
public class MyConnectionLifecycleInterceptor implements ConnectionLifecycleInterceptor {
private Log log;
public ConnectionLifecycleInterceptor init(MysqlConnection conn, Properties props, Log log) {
this.log = log;
return this;
}
public void destroy() {
// Cleanup
}
public void createNewSession() {
log.logInfo("New database session created");
}
public void transactionBegun() {
log.logInfo("Transaction started");
}
public void transactionCompleted() {
log.logInfo("Transaction completed");
}
}
// Configure interceptor in URL
String url = "jdbc:mysql://localhost:3306/mydb" +
"?connectionLifecycleInterceptors=com.mycompany.MyConnectionLifecycleInterceptor";
Connection conn = DriverManager.getConnection(url, "user", "pass");
// Lifecycle events will be intercepted
conn.setAutoCommit(false); // transactionBegun() called
stmt.executeUpdate("INSERT INTO users (name) VALUES ('Alice')");
conn.commit(); // transactionCompleted() calledBuilt-in interceptor for scanning result sets.
package com.mysql.cj.jdbc.interceptors;
public class ResultSetScannerInterceptor implements QueryInterceptor {
// Scans result sets for specific patterns
// Configure via properties:
// resultSetScannerRegex - regex pattern to match
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log);
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery);
public boolean executeTopLevelOnly();
public void destroy();
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
T originalResultSet, ServerSession serverSession);
}Usage:
// Scan result sets for sensitive data patterns
String url = "jdbc:mysql://localhost:3306/mydb" +
"?queryInterceptors=com.mysql.cj.jdbc.interceptors.ResultSetScannerInterceptor" +
"&resultSetScannerRegex=\\d{3}-\\d{2}-\\d{4}"; // SSN pattern
Connection conn = DriverManager.getConnection(url, "user", "pass");
// Will scan all result sets and log matchesBuilt-in interceptor for tracking server status changes.
package com.mysql.cj.jdbc.interceptors;
public class ServerStatusDiffInterceptor implements QueryInterceptor {
// Tracks changes in server status variables before/after queries
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log);
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery);
public boolean executeTopLevelOnly();
public void destroy();
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
T originalResultSet, ServerSession serverSession);
}Usage:
// Track server status changes
String url = "jdbc:mysql://localhost:3306/mydb" +
"?queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor";
Connection conn = DriverManager.getConnection(url, "user", "pass");
// Will log changes in server status variablesBuilt-in interceptor for associating sessions with application context.
package com.mysql.cj.jdbc.interceptors;
public class SessionAssociationInterceptor implements ConnectionLifecycleInterceptor {
// Associates session with application context
public ConnectionLifecycleInterceptor init(MysqlConnection conn, Properties props, Log log);
public void destroy();
public void createNewSession();
public void transactionBegun();
public void transactionCompleted();
}You can configure multiple interceptors by separating them with commas.
Usage:
// Configure multiple query interceptors
String url = "jdbc:mysql://localhost:3306/mydb" +
"?queryInterceptors=" +
"com.mycompany.LoggingInterceptor," +
"com.mycompany.MetricsInterceptor," +
"com.mycompany.SecurityInterceptor";
// Configure multiple connection lifecycle interceptors
String url2 = "jdbc:mysql://localhost:3306/mydb" +
"?connectionLifecycleInterceptors=" +
"com.mycompany.PoolingInterceptor," +
"com.mycompany.AuditInterceptor";
Connection conn = DriverManager.getConnection(url, "user", "pass");Complete example showing advanced query interception:
public class MetricsQueryInterceptor implements QueryInterceptor {
private Log log;
private Map<String, Long> queryTimes = new ConcurrentHashMap<>();
private Map<String, AtomicLong> queryCount = new ConcurrentHashMap<>();
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
this.log = log;
return this;
}
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery) {
String query = sql.get();
queryTimes.put(query, System.currentTimeMillis());
queryCount.computeIfAbsent(query, k -> new AtomicLong()).incrementAndGet();
return null;
}
public boolean executeTopLevelOnly() {
return true;
}
public void destroy() {
// Log metrics summary
log.logInfo("Query Metrics Summary:");
for (Map.Entry<String, AtomicLong> entry : queryCount.entrySet()) {
log.logInfo(entry.getKey() + ": executed " + entry.getValue() + " times");
}
}
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
T originalResultSet, ServerSession serverSession) {
String query = sql.get();
Long startTime = queryTimes.remove(query);
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
if (duration > 1000) {
log.logWarn("Slow query (" + duration + "ms): " + query);
}
}
return originalResultSet;
}
}Query interceptors can access parameter bindings:
public class ParameterLoggingInterceptor implements QueryInterceptor {
private Log log;
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
this.log = log;
return this;
}
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery) {
if (interceptedQuery instanceof PreparedQuery) {
PreparedQuery<?> pq = (PreparedQuery<?>) interceptedQuery;
ParameterBindings bindings = pq.getParameterBindings();
StringBuilder sb = new StringBuilder("Query: ");
sb.append(sql.get());
sb.append("\nParameters: ");
sb.append(bindings.toString(true));
log.logDebug(sb.toString());
}
return null;
}
public boolean executeTopLevelOnly() {
return false;
}
public void destroy() {}
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
T originalResultSet, ServerSession serverSession) {
return originalResultSet;
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-mysql--mysql-connector-j