0
# Interceptors
1
2
Query and connection lifecycle interceptors for customizing driver behavior. Interceptors allow you to hook into query execution and connection events.
3
4
## Capabilities
5
6
### Query Interceptor
7
8
Interface for intercepting query execution.
9
10
```java { .api }
11
package com.mysql.cj.interceptors;
12
13
public interface QueryInterceptor {
14
// Initialize interceptor
15
QueryInterceptor init(MysqlConnection conn, Properties props, Log log);
16
17
// Pre-process query (before execution)
18
<T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery);
19
20
// Check if should execute only at top level
21
boolean executeTopLevelOnly();
22
23
// Destroy interceptor
24
void destroy();
25
26
// Post-process query (after execution)
27
<T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
28
T originalResultSet, ServerSession serverSession);
29
}
30
```
31
32
Usage:
33
34
```java
35
// Implement custom query interceptor
36
public class MyQueryInterceptor implements QueryInterceptor {
37
private Log log;
38
39
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
40
this.log = log;
41
return this;
42
}
43
44
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery) {
45
log.logInfo("Executing query: " + sql.get());
46
return null; // null means proceed with execution
47
}
48
49
public boolean executeTopLevelOnly() {
50
return false; // Also intercept nested queries
51
}
52
53
public void destroy() {
54
// Cleanup
55
}
56
57
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
58
T originalResultSet, ServerSession serverSession) {
59
log.logInfo("Query completed: " + sql.get());
60
return originalResultSet;
61
}
62
}
63
64
// Configure interceptor in URL
65
String url = "jdbc:mysql://localhost:3306/mydb" +
66
"?queryInterceptors=com.mycompany.MyQueryInterceptor";
67
Connection conn = DriverManager.getConnection(url, "user", "pass");
68
69
// All queries will be intercepted
70
Statement stmt = conn.createStatement();
71
stmt.executeQuery("SELECT * FROM users");
72
```
73
74
### Connection Lifecycle Interceptor
75
76
Interface for intercepting connection lifecycle events.
77
78
```java { .api }
79
package com.mysql.cj.jdbc.interceptors;
80
81
public interface ConnectionLifecycleInterceptor {
82
// Initialize interceptor
83
ConnectionLifecycleInterceptor init(MysqlConnection conn, Properties props, Log log);
84
85
// Destroy interceptor
86
void destroy();
87
88
// Called when new session is created
89
void createNewSession();
90
91
// Called when transaction begins
92
void transactionBegun();
93
94
// Called when transaction completes (commit or rollback)
95
void transactionCompleted();
96
}
97
```
98
99
Usage:
100
101
```java
102
// Implement custom connection lifecycle interceptor
103
public class MyConnectionLifecycleInterceptor implements ConnectionLifecycleInterceptor {
104
private Log log;
105
106
public ConnectionLifecycleInterceptor init(MysqlConnection conn, Properties props, Log log) {
107
this.log = log;
108
return this;
109
}
110
111
public void destroy() {
112
// Cleanup
113
}
114
115
public void createNewSession() {
116
log.logInfo("New database session created");
117
}
118
119
public void transactionBegun() {
120
log.logInfo("Transaction started");
121
}
122
123
public void transactionCompleted() {
124
log.logInfo("Transaction completed");
125
}
126
}
127
128
// Configure interceptor in URL
129
String url = "jdbc:mysql://localhost:3306/mydb" +
130
"?connectionLifecycleInterceptors=com.mycompany.MyConnectionLifecycleInterceptor";
131
Connection conn = DriverManager.getConnection(url, "user", "pass");
132
133
// Lifecycle events will be intercepted
134
conn.setAutoCommit(false); // transactionBegun() called
135
stmt.executeUpdate("INSERT INTO users (name) VALUES ('Alice')");
136
conn.commit(); // transactionCompleted() called
137
```
138
139
### Result Set Scanner Interceptor
140
141
Built-in interceptor for scanning result sets.
142
143
```java { .api }
144
package com.mysql.cj.jdbc.interceptors;
145
146
public class ResultSetScannerInterceptor implements QueryInterceptor {
147
// Scans result sets for specific patterns
148
// Configure via properties:
149
// resultSetScannerRegex - regex pattern to match
150
151
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log);
152
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery);
153
public boolean executeTopLevelOnly();
154
public void destroy();
155
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
156
T originalResultSet, ServerSession serverSession);
157
}
158
```
159
160
Usage:
161
162
```java
163
// Scan result sets for sensitive data patterns
164
String url = "jdbc:mysql://localhost:3306/mydb" +
165
"?queryInterceptors=com.mysql.cj.jdbc.interceptors.ResultSetScannerInterceptor" +
166
"&resultSetScannerRegex=\\d{3}-\\d{2}-\\d{4}"; // SSN pattern
167
Connection conn = DriverManager.getConnection(url, "user", "pass");
168
169
// Will scan all result sets and log matches
170
```
171
172
### Server Status Diff Interceptor
173
174
Built-in interceptor for tracking server status changes.
175
176
```java { .api }
177
package com.mysql.cj.jdbc.interceptors;
178
179
public class ServerStatusDiffInterceptor implements QueryInterceptor {
180
// Tracks changes in server status variables before/after queries
181
182
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log);
183
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery);
184
public boolean executeTopLevelOnly();
185
public void destroy();
186
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
187
T originalResultSet, ServerSession serverSession);
188
}
189
```
190
191
Usage:
192
193
```java
194
// Track server status changes
195
String url = "jdbc:mysql://localhost:3306/mydb" +
196
"?queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor";
197
Connection conn = DriverManager.getConnection(url, "user", "pass");
198
199
// Will log changes in server status variables
200
```
201
202
### Session Association Interceptor
203
204
Built-in interceptor for associating sessions with application context.
205
206
```java { .api }
207
package com.mysql.cj.jdbc.interceptors;
208
209
public class SessionAssociationInterceptor implements ConnectionLifecycleInterceptor {
210
// Associates session with application context
211
212
public ConnectionLifecycleInterceptor init(MysqlConnection conn, Properties props, Log log);
213
public void destroy();
214
public void createNewSession();
215
public void transactionBegun();
216
public void transactionCompleted();
217
}
218
```
219
220
### Multiple Interceptors
221
222
You can configure multiple interceptors by separating them with commas.
223
224
Usage:
225
226
```java
227
// Configure multiple query interceptors
228
String url = "jdbc:mysql://localhost:3306/mydb" +
229
"?queryInterceptors=" +
230
"com.mycompany.LoggingInterceptor," +
231
"com.mycompany.MetricsInterceptor," +
232
"com.mycompany.SecurityInterceptor";
233
234
// Configure multiple connection lifecycle interceptors
235
String url2 = "jdbc:mysql://localhost:3306/mydb" +
236
"?connectionLifecycleInterceptors=" +
237
"com.mycompany.PoolingInterceptor," +
238
"com.mycompany.AuditInterceptor";
239
240
Connection conn = DriverManager.getConnection(url, "user", "pass");
241
```
242
243
### Advanced Query Interceptor Example
244
245
Complete example showing advanced query interception:
246
247
```java
248
public class MetricsQueryInterceptor implements QueryInterceptor {
249
private Log log;
250
private Map<String, Long> queryTimes = new ConcurrentHashMap<>();
251
private Map<String, AtomicLong> queryCount = new ConcurrentHashMap<>();
252
253
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
254
this.log = log;
255
return this;
256
}
257
258
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery) {
259
String query = sql.get();
260
queryTimes.put(query, System.currentTimeMillis());
261
queryCount.computeIfAbsent(query, k -> new AtomicLong()).incrementAndGet();
262
return null;
263
}
264
265
public boolean executeTopLevelOnly() {
266
return true;
267
}
268
269
public void destroy() {
270
// Log metrics summary
271
log.logInfo("Query Metrics Summary:");
272
for (Map.Entry<String, AtomicLong> entry : queryCount.entrySet()) {
273
log.logInfo(entry.getKey() + ": executed " + entry.getValue() + " times");
274
}
275
}
276
277
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
278
T originalResultSet, ServerSession serverSession) {
279
String query = sql.get();
280
Long startTime = queryTimes.remove(query);
281
if (startTime != null) {
282
long duration = System.currentTimeMillis() - startTime;
283
if (duration > 1000) {
284
log.logWarn("Slow query (" + duration + "ms): " + query);
285
}
286
}
287
return originalResultSet;
288
}
289
}
290
```
291
292
### Parameter Bindings Access
293
294
Query interceptors can access parameter bindings:
295
296
```java
297
public class ParameterLoggingInterceptor implements QueryInterceptor {
298
private Log log;
299
300
public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
301
this.log = log;
302
return this;
303
}
304
305
public <T extends Resultset> T preProcess(Supplier<String> sql, Query interceptedQuery) {
306
if (interceptedQuery instanceof PreparedQuery) {
307
PreparedQuery<?> pq = (PreparedQuery<?>) interceptedQuery;
308
ParameterBindings bindings = pq.getParameterBindings();
309
310
StringBuilder sb = new StringBuilder("Query: ");
311
sb.append(sql.get());
312
sb.append("\nParameters: ");
313
sb.append(bindings.toString(true));
314
315
log.logDebug(sb.toString());
316
}
317
return null;
318
}
319
320
public boolean executeTopLevelOnly() {
321
return false;
322
}
323
324
public void destroy() {}
325
326
public <T extends Resultset> T postProcess(Supplier<String> sql, Query interceptedQuery,
327
T originalResultSet, ServerSession serverSession) {
328
return originalResultSet;
329
}
330
}
331
```
332