0
# JDBC Advanced Features
1
2
Advanced JDBC capabilities including connection pooling, distributed transactions (XA), batch operations, and server-side prepared statements. These features enable high-performance and enterprise-grade database applications.
3
4
## Capabilities
5
6
### Connection Pooling
7
8
Connection pooling support through PooledConnection and ConnectionPoolDataSource.
9
10
```java { .api }
11
package com.mysql.cj.jdbc;
12
13
public class MysqlConnectionPoolDataSource extends MysqlDataSource
14
implements javax.sql.ConnectionPoolDataSource {
15
16
// Pooled connection creation
17
public PooledConnection getPooledConnection() throws SQLException;
18
public PooledConnection getPooledConnection(String user, String password) throws SQLException;
19
}
20
21
public class MysqlPooledConnection implements javax.sql.PooledConnection {
22
// Constructor
23
public MysqlPooledConnection(JdbcConnection connection);
24
25
// Get logical connection
26
public Connection getConnection() throws SQLException;
27
28
// Close physical connection
29
public void close() throws SQLException;
30
31
// Event listeners
32
public void addConnectionEventListener(ConnectionEventListener listener);
33
public void removeConnectionEventListener(ConnectionEventListener listener);
34
35
// Statement event listeners
36
public void addStatementEventListener(StatementEventListener listener);
37
public void removeStatementEventListener(StatementEventListener listener);
38
}
39
```
40
41
Usage:
42
43
```java
44
// Create connection pool data source
45
MysqlConnectionPoolDataSource cpds = new MysqlConnectionPoolDataSource();
46
cpds.setURL("jdbc:mysql://localhost:3306/mydb");
47
cpds.setUser("root");
48
cpds.setPassword("password");
49
50
// Get pooled connection
51
PooledConnection pooledConn = cpds.getPooledConnection();
52
53
// Add connection event listener
54
pooledConn.addConnectionEventListener(new ConnectionEventListener() {
55
public void connectionClosed(ConnectionEvent event) {
56
System.out.println("Connection closed");
57
}
58
59
public void connectionErrorOccurred(ConnectionEvent event) {
60
System.out.println("Connection error: " + event.getSQLException());
61
}
62
});
63
64
// Get logical connection from pool
65
Connection conn = pooledConn.getConnection();
66
// Use connection...
67
conn.close(); // Returns to pool
68
69
// Close physical connection
70
pooledConn.close();
71
```
72
73
### XA Distributed Transactions
74
75
Support for distributed transactions using the XA protocol.
76
77
```java { .api }
78
package com.mysql.cj.jdbc;
79
80
public class MysqlXADataSource extends MysqlConnectionPoolDataSource
81
implements javax.sql.XADataSource {
82
83
// XA connection creation
84
public XAConnection getXAConnection() throws SQLException;
85
public XAConnection getXAConnection(String user, String password) throws SQLException;
86
}
87
88
public class MysqlXAConnection extends MysqlPooledConnection implements javax.sql.XAConnection {
89
// Constructor
90
public MysqlXAConnection(JdbcConnection connection, boolean logXaCommands);
91
92
// Get XA resource
93
public XAResource getXAResource() throws SQLException;
94
}
95
96
public class SuspendableXAConnection extends MysqlXAConnection {
97
// Constructor
98
public SuspendableXAConnection(JdbcConnection connection);
99
100
// XA resource with suspend/resume support
101
public XAResource getXAResource() throws SQLException;
102
}
103
104
public class MysqlXid implements javax.transaction.xa.Xid {
105
// Constructor
106
public MysqlXid(byte[] globalTransactionId, byte[] branchQualifier, int formatId);
107
108
// Xid components
109
public byte[] getGlobalTransactionId();
110
public byte[] getBranchQualifier();
111
public int getFormatId();
112
}
113
```
114
115
Usage:
116
117
```java
118
// Create XA data source
119
MysqlXADataSource xads = new MysqlXADataSource();
120
xads.setURL("jdbc:mysql://localhost:3306/mydb");
121
xads.setUser("root");
122
xads.setPassword("password");
123
124
// Get XA connection
125
XAConnection xaConn = xads.getXAConnection();
126
XAResource xaRes = xaConn.getXAResource();
127
128
// Create XID for transaction
129
Xid xid = new MysqlXid(
130
"global-tx-1".getBytes(),
131
"branch-1".getBytes(),
132
1
133
);
134
135
try {
136
// Start XA transaction
137
xaRes.start(xid, XAResource.TMNOFLAGS);
138
139
// Get connection and perform work
140
Connection conn = xaConn.getConnection();
141
Statement stmt = conn.createStatement();
142
stmt.executeUpdate("INSERT INTO accounts (name, balance) VALUES ('Alice', 1000)");
143
stmt.close();
144
145
// End XA transaction
146
xaRes.end(xid, XAResource.TMSUCCESS);
147
148
// Prepare phase
149
int prepareResult = xaRes.prepare(xid);
150
151
if (prepareResult == XAResource.XA_OK) {
152
// Commit phase
153
xaRes.commit(xid, false);
154
System.out.println("Transaction committed");
155
}
156
} catch (XAException e) {
157
// Rollback on error
158
try {
159
xaRes.rollback(xid);
160
} catch (XAException rollbackEx) {
161
rollbackEx.printStackTrace();
162
}
163
e.printStackTrace();
164
} finally {
165
xaConn.close();
166
}
167
```
168
169
### Batch Operations
170
171
Efficient batch execution of multiple SQL statements.
172
173
```java { .api }
174
// Batch operations are part of Statement interfaces
175
176
// Statement batch operations
177
public interface Statement {
178
void addBatch(String sql) throws SQLException;
179
void clearBatch() throws SQLException;
180
int[] executeBatch() throws SQLException;
181
long[] executeLargeBatch() throws SQLException;
182
}
183
184
// PreparedStatement batch operations
185
public interface PreparedStatement extends Statement {
186
void addBatch() throws SQLException;
187
// Inherits executeBatch() and clearBatch() from Statement
188
}
189
```
190
191
Usage:
192
193
```java
194
// Statement batch
195
Statement stmt = conn.createStatement();
196
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Alice', 25)");
197
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Bob', 30)");
198
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Charlie', 35)");
199
200
int[] updateCounts = stmt.executeBatch();
201
System.out.println("Batch executed: " + updateCounts.length + " statements");
202
203
// PreparedStatement batch
204
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
205
PreparedStatement pstmt = conn.prepareStatement(sql);
206
207
pstmt.setString(1, "David");
208
pstmt.setInt(2, 28);
209
pstmt.addBatch();
210
211
pstmt.setString(1, "Eve");
212
pstmt.setInt(2, 32);
213
pstmt.addBatch();
214
215
pstmt.setString(1, "Frank");
216
pstmt.setInt(2, 27);
217
pstmt.addBatch();
218
219
int[] batchResults = pstmt.executeBatch();
220
System.out.println("Inserted " + batchResults.length + " rows");
221
222
// Enable rewriteBatchedStatements for better performance
223
// Set in connection URL: ?rewriteBatchedStatements=true
224
```
225
226
### Server-Side Prepared Statements
227
228
Server-side prepared statements for enhanced performance with repeated executions.
229
230
```java { .api }
231
package com.mysql.cj.jdbc;
232
233
public class ServerPreparedStatement extends ClientPreparedStatement {
234
// Server-side prepared statement implementation
235
// Inherits all PreparedStatement methods but executes on server
236
237
// Additional server-side specific behavior
238
// - Statement is compiled once on server
239
// - Parameters sent separately for each execution
240
// - Better performance for repeated executions
241
// - Uses binary protocol
242
}
243
244
// Connection methods for explicit server-side preparation
245
public interface JdbcConnection extends Connection {
246
PreparedStatement serverPrepareStatement(String sql) throws SQLException;
247
PreparedStatement serverPrepareStatement(String sql, int autoGeneratedKeys) throws SQLException;
248
PreparedStatement serverPrepareStatement(String sql, int resultSetType, int resultSetConcurrency)
249
throws SQLException;
250
PreparedStatement serverPrepareStatement(String sql, int resultSetType, int resultSetConcurrency,
251
int resultSetHoldability) throws SQLException;
252
PreparedStatement serverPrepareStatement(String sql, int[] autoGeneratedKeyIndexes)
253
throws SQLException;
254
PreparedStatement serverPrepareStatement(String sql, String[] autoGeneratedKeyColNames)
255
throws SQLException;
256
}
257
```
258
259
Usage:
260
261
```java
262
// Enable server-side prepared statements via connection property
263
String url = "jdbc:mysql://localhost:3306/mydb?useServerPrepStmts=true";
264
Connection conn = DriverManager.getConnection(url, "root", "password");
265
266
// Or explicitly create server-side prepared statement
267
JdbcConnection mysqlConn = conn.unwrap(JdbcConnection.class);
268
PreparedStatement pstmt = mysqlConn.serverPrepareStatement(
269
"SELECT * FROM users WHERE age > ?"
270
);
271
272
// Execute multiple times - benefits from server-side caching
273
for (int age = 18; age <= 50; age += 10) {
274
pstmt.setInt(1, age);
275
ResultSet rs = pstmt.executeQuery();
276
// Process results...
277
rs.close();
278
}
279
280
pstmt.close();
281
282
// Configure prepared statement cache
283
// Set in URL: ?cachePrepStmts=true&prepStmtCacheSize=250&prepStmtCacheSqlLimit=2048
284
```
285
286
### Statement Wrappers
287
288
Wrapper classes for pooled connection statement management.
289
290
```java { .api }
291
package com.mysql.cj.jdbc;
292
293
public class StatementWrapper implements Statement {
294
// Wraps statements for pooled connections
295
// Delegates all calls to underlying statement
296
// Tracks lifecycle for proper cleanup
297
298
protected Statement wrappedStmt;
299
protected ConnectionWrapper connectionWrapper;
300
301
public StatementWrapper(ConnectionWrapper c, MysqlPooledConnection conn, Statement toWrap);
302
303
// All Statement methods delegated to wrappedStmt
304
// Close notifications sent to connection wrapper
305
}
306
307
public class PreparedStatementWrapper extends StatementWrapper implements PreparedStatement {
308
// Wraps prepared statements for pooled connections
309
310
protected PreparedStatement wrappedPrepStmt;
311
312
public PreparedStatementWrapper(ConnectionWrapper c, MysqlPooledConnection conn,
313
PreparedStatement toWrap);
314
315
// All PreparedStatement methods delegated to wrappedPrepStmt
316
}
317
318
public class CallableStatementWrapper extends PreparedStatementWrapper
319
implements CallableStatement {
320
// Wraps callable statements for pooled connections
321
322
protected CallableStatement wrappedCallableStmt;
323
324
public CallableStatementWrapper(ConnectionWrapper c, MysqlPooledConnection conn,
325
CallableStatement toWrap);
326
327
// All CallableStatement methods delegated to wrappedCallableStmt
328
}
329
330
public class ConnectionWrapper implements JdbcConnection {
331
// Wraps connections for pooled connection management
332
333
protected JdbcConnection wrappedConnection;
334
protected MysqlPooledConnection pooledConnection;
335
336
public ConnectionWrapper(MysqlPooledConnection pooledConnection, JdbcConnection connection);
337
338
// All Connection methods delegated to wrappedConnection
339
// Statement creation returns wrapped statements
340
// Close notifications sent to pooled connection
341
}
342
```
343
344
### Abandoned Connection Cleanup
345
346
Automatic cleanup of connections that are not properly closed.
347
348
```java { .api }
349
package com.mysql.cj.jdbc;
350
351
public class AbandonedConnectionCleanupThread extends Thread {
352
// Singleton thread for cleaning up abandoned connections
353
354
// Check if cleanup thread is running
355
public static boolean isAlive();
356
357
// Manually trigger cleanup (normally automatic)
358
public static void checkedShutdown();
359
360
// Shutdown cleanup thread
361
public static void uncheckedShutdown();
362
}
363
```
364
365
Usage:
366
367
```java
368
// The cleanup thread is automatically started when needed
369
// and runs in the background
370
371
// To explicitly shutdown (e.g., in web application context listener):
372
public class MyContextListener implements ServletContextListener {
373
public void contextDestroyed(ServletContextEvent event) {
374
try {
375
AbandonedConnectionCleanupThread.checkedShutdown();
376
} catch (Exception e) {
377
e.printStackTrace();
378
}
379
}
380
}
381
```
382
383
### Result Set Factory
384
385
Factory for creating different types of result sets.
386
387
```java { .api }
388
package com.mysql.cj.jdbc.result;
389
390
public class ResultSetFactory {
391
// Create result set from result data
392
public static ResultSet createFromResultsetRows(
393
int resultSetType,
394
int resultSetConcurrency,
395
ResultsetRows rows,
396
JdbcConnection conn,
397
StatementImpl stmt
398
) throws SQLException;
399
400
// Result set type constants (from java.sql.ResultSet)
401
// TYPE_FORWARD_ONLY - cursor can only move forward
402
// TYPE_SCROLL_INSENSITIVE - scrollable, not sensitive to changes
403
// TYPE_SCROLL_SENSITIVE - scrollable, sensitive to changes
404
405
// Result set concurrency constants
406
// CONCUR_READ_ONLY - read-only result set
407
// CONCUR_UPDATABLE - updatable result set
408
}
409
```
410
411
### Parameter Bindings
412
413
Interface to allow PreparedStatement implementations to expose their parameter bindings to QueryInterceptors.
414
415
```java { .api }
416
package com.mysql.cj.jdbc;
417
418
import java.io.InputStream;
419
import java.io.Reader;
420
import java.math.BigDecimal;
421
import java.math.BigInteger;
422
import java.net.URL;
423
import java.sql.Array;
424
import java.sql.Clob;
425
import java.sql.Date;
426
import java.sql.Ref;
427
import java.sql.SQLException;
428
import java.sql.Time;
429
import java.sql.Timestamp;
430
431
/**
432
* Interface to allow PreparedStatement implementations to expose their parameter bindings to QueryInterceptors.
433
*/
434
public interface ParameterBindings {
435
Array getArray(int parameterIndex) throws SQLException;
436
InputStream getAsciiStream(int parameterIndex) throws SQLException;
437
BigDecimal getBigDecimal(int parameterIndex) throws SQLException;
438
InputStream getBinaryStream(int parameterIndex) throws SQLException;
439
java.sql.Blob getBlob(int parameterIndex) throws SQLException;
440
boolean getBoolean(int parameterIndex) throws SQLException;
441
byte getByte(int parameterIndex) throws SQLException;
442
byte[] getBytes(int parameterIndex) throws SQLException;
443
Reader getCharacterStream(int parameterIndex) throws SQLException;
444
Clob getClob(int parameterIndex) throws SQLException;
445
Date getDate(int parameterIndex) throws SQLException;
446
double getDouble(int parameterIndex) throws SQLException;
447
float getFloat(int parameterIndex) throws SQLException;
448
int getInt(int parameterIndex) throws SQLException;
449
BigInteger getBigInteger(int parameterIndex) throws SQLException;
450
long getLong(int parameterIndex) throws SQLException;
451
Reader getNCharacterStream(int parameterIndex) throws SQLException;
452
Reader getNClob(int parameterIndex) throws SQLException;
453
Object getObject(int parameterIndex) throws SQLException;
454
Ref getRef(int parameterIndex) throws SQLException;
455
short getShort(int parameterIndex) throws SQLException;
456
String getString(int parameterIndex) throws SQLException;
457
Time getTime(int parameterIndex) throws SQLException;
458
Timestamp getTimestamp(int parameterIndex) throws SQLException;
459
URL getURL(int parameterIndex) throws SQLException;
460
boolean isNull(int parameterIndex) throws SQLException;
461
}
462
```
463
464
### Streaming Results
465
466
Support for streaming large result sets without loading all data into memory.
467
468
```java { .api }
469
package com.mysql.cj.jdbc;
470
471
public interface JdbcStatement extends Statement {
472
// Enable streaming results (one row at a time)
473
void enableStreamingResults() throws SQLException;
474
475
// Disable streaming results (default behavior)
476
void disableStreamingResults() throws SQLException;
477
}
478
```
479
480
Usage:
481
482
```java
483
// Method 1: Use Statement.setFetchSize(Integer.MIN_VALUE)
484
Statement stmt = conn.createStatement(
485
ResultSet.TYPE_FORWARD_ONLY,
486
ResultSet.CONCUR_READ_ONLY
487
);
488
stmt.setFetchSize(Integer.MIN_VALUE);
489
490
ResultSet rs = stmt.executeQuery("SELECT * FROM large_table");
491
while (rs.next()) {
492
// Process one row at a time
493
// Memory usage remains constant
494
}
495
496
// Method 2: Use enableStreamingResults()
497
JdbcStatement mysqlStmt = stmt.unwrap(JdbcStatement.class);
498
mysqlStmt.enableStreamingResults();
499
500
ResultSet rs2 = mysqlStmt.executeQuery("SELECT * FROM another_large_table");
501
while (rs2.next()) {
502
// Process streaming results
503
}
504
505
// Important: Only one streaming result set can be open per connection
506
// Close result set before executing another query
507
rs.close();
508
stmt.close();
509
```
510
511
### Large Update Counts
512
513
Support for update counts exceeding Integer.MAX_VALUE.
514
515
```java { .api }
516
package com.mysql.cj.jdbc;
517
518
public interface JdbcStatement extends Statement {
519
// Execute with large update count
520
long executeLargeUpdate(String sql) throws SQLException;
521
long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException;
522
long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException;
523
long executeLargeUpdate(String sql, String[] columnNames) throws SQLException;
524
525
// Get large update count
526
long getLargeUpdateCount() throws SQLException;
527
528
// Large batch execution
529
long[] executeLargeBatch() throws SQLException;
530
531
// Large max rows
532
void setLargeMaxRows(long max) throws SQLException;
533
long getLargeMaxRows() throws SQLException;
534
}
535
536
public interface JdbcPreparedStatement extends PreparedStatement {
537
// Execute with large update count
538
long executeLargeUpdate() throws SQLException;
539
}
540
```
541
542
Usage:
543
544
```java
545
Statement stmt = conn.createStatement();
546
547
// Execute update returning large count
548
long rowsAffected = stmt.executeLargeUpdate(
549
"DELETE FROM logs WHERE timestamp < '2020-01-01'"
550
);
551
System.out.println("Deleted " + rowsAffected + " rows");
552
553
// Large batch execution
554
stmt.addBatch("UPDATE table1 SET col = 'value'");
555
stmt.addBatch("UPDATE table2 SET col = 'value'");
556
long[] largeCounts = stmt.executeLargeBatch();
557
558
// Set large max rows
559
stmt.setLargeMaxRows(10_000_000_000L);
560
long maxRows = stmt.getLargeMaxRows();
561
```
562
563
### Local Infile
564
565
Support for LOAD DATA LOCAL INFILE operations.
566
567
```java { .api }
568
package com.mysql.cj.jdbc;
569
570
public interface JdbcStatement extends Statement {
571
// Set input stream for LOCAL INFILE
572
void setLocalInfileInputStream(InputStream stream);
573
574
// Get input stream for LOCAL INFILE
575
InputStream getLocalInfileInputStream();
576
}
577
```
578
579
Usage:
580
581
```java
582
// Enable LOCAL INFILE in connection
583
String url = "jdbc:mysql://localhost:3306/mydb?allowLoadLocalInfile=true";
584
Connection conn = DriverManager.getConnection(url, "root", "password");
585
586
Statement stmt = conn.createStatement();
587
JdbcStatement mysqlStmt = stmt.unwrap(JdbcStatement.class);
588
589
// Provide input stream for LOAD DATA LOCAL INFILE
590
InputStream fileInput = new FileInputStream("data.csv");
591
mysqlStmt.setLocalInfileInputStream(fileInput);
592
593
// Execute LOAD DATA LOCAL INFILE
594
stmt.execute(
595
"LOAD DATA LOCAL INFILE 'data.csv' INTO TABLE mytable " +
596
"FIELDS TERMINATED BY ',' " +
597
"LINES TERMINATED BY '\\n'"
598
);
599
600
fileInput.close();
601
stmt.close();
602
```
603
604
### JDBC Property Set
605
606
Configuration properties specific to JDBC implementation.
607
608
```java { .api }
609
package com.mysql.cj.jdbc;
610
611
public interface JdbcPropertySet extends com.mysql.cj.conf.PropertySet {
612
// Expose all connection properties as DriverPropertyInfo
613
DriverPropertyInfo[] exposeAsProperties(Properties info) throws SQLException;
614
}
615
616
public class JdbcPropertySetImpl implements JdbcPropertySet {
617
// Implementation of JDBC property set
618
619
public JdbcPropertySetImpl();
620
621
public void initializeProperties(Properties props);
622
623
public DriverPropertyInfo[] exposeAsProperties(Properties info) throws SQLException;
624
}
625
```
626
627
### Mini Admin Utilities
628
629
Utility functions for administrative operations.
630
631
```java { .api }
632
package com.mysql.cj.jdbc.admin;
633
634
public class MiniAdmin {
635
// Constructor
636
public MiniAdmin(String jdbcUrl) throws SQLException;
637
public MiniAdmin(String jdbcUrl, Properties props) throws SQLException;
638
639
// Shutdown MySQL server
640
public void shutdown() throws SQLException;
641
}
642
```
643
644
Usage:
645
646
```java
647
// Create admin instance
648
MiniAdmin admin = new MiniAdmin("jdbc:mysql://localhost:3306/");
649
650
// Shutdown MySQL server
651
admin.shutdown();
652
```
653
654
### C3P0 Integration
655
656
Connection tester for C3P0 connection pool integration.
657
658
```java { .api }
659
package com.mysql.cj.jdbc.integration.c3p0;
660
661
public class MysqlConnectionTester implements com.mchange.v2.c3p0.ConnectionTester {
662
// Test connection liveness using COM_PING
663
public int activeCheckConnection(Connection c);
664
665
// Test connection on checkout
666
public int statusOnException(Connection c, Throwable t);
667
}
668
```
669
670
Usage with C3P0:
671
672
```java
673
// Configure C3P0 data source with MySQL connection tester
674
ComboPooledDataSource cpds = new ComboPooledDataSource();
675
cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
676
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
677
cpds.setUser("root");
678
cpds.setPassword("password");
679
680
// Use MySQL-specific connection tester
681
cpds.setConnectionTesterClassName(
682
"com.mysql.cj.jdbc.integration.c3p0.MysqlConnectionTester"
683
);
684
685
// Pool configuration
686
cpds.setMinPoolSize(5);
687
cpds.setMaxPoolSize(20);
688
cpds.setAcquireIncrement(5);
689
cpds.setTestConnectionOnCheckout(true);
690
691
Connection conn = cpds.getConnection();
692
```
693
694
### Iterator Block
695
696
Helper for iterating over result sets.
697
698
```java { .api }
699
package com.mysql.cj.jdbc;
700
701
public abstract class IterateBlock<T> {
702
// Constructor
703
public IterateBlock();
704
705
// Override this method to process each row
706
public abstract void forEach(T each) throws SQLException;
707
708
// Execute iteration
709
public final void doForAll(Iterator<T> iterator) throws SQLException;
710
}
711
```
712
713
Usage:
714
715
```java
716
// Custom iteration logic
717
IterateBlock<Row> rowProcessor = new IterateBlock<Row>() {
718
@Override
719
public void forEach(Row row) throws SQLException {
720
// Process each row
721
System.out.println("Processing row: " + row);
722
}
723
};
724
725
// Execute iteration
726
// rowProcessor.doForAll(rowIterator);
727
```
728
729
### Close Options
730
731
Enumeration for connection close options.
732
733
```java { .api }
734
package com.mysql.cj.jdbc;
735
736
public enum CloseOption {
737
IMPLICIT, // Close operation initiated internally by a clean up routine
738
FORCED, // A forced, hard close
739
ROLLBACK, // Allow rollback during the close operation
740
PROPAGATE, // Allow propagating the close operation to dependents and owner objects
741
NO_CACHE; // Does not allow caching the closing object
742
743
public boolean in(CloseOption... options);
744
public boolean notIn(CloseOption... options);
745
}
746
```
747
748
### Connection Change User
749
750
Support for changing the authenticated user on an existing connection.
751
752
```java { .api }
753
package com.mysql.cj.jdbc;
754
755
public interface JdbcConnection extends Connection {
756
// Change authenticated user
757
void changeUser(String userName, String newPassword) throws SQLException;
758
}
759
```
760
761
Usage:
762
763
```java
764
Connection conn = DriverManager.getConnection(url, "user1", "pass1");
765
766
// Change to different user
767
JdbcConnection mysqlConn = conn.unwrap(JdbcConnection.class);
768
mysqlConn.changeUser("user2", "pass2");
769
770
// Connection now authenticated as user2
771
```
772