JDBC Type 4 driver for MySQL with X DevAPI support for document store operations
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.
Connection pooling support through PooledConnection and ConnectionPoolDataSource.
package com.mysql.cj.jdbc;
public class MysqlConnectionPoolDataSource extends MysqlDataSource
implements javax.sql.ConnectionPoolDataSource {
// Pooled connection creation
public PooledConnection getPooledConnection() throws SQLException;
public PooledConnection getPooledConnection(String user, String password) throws SQLException;
}
public class MysqlPooledConnection implements javax.sql.PooledConnection {
// Constructor
public MysqlPooledConnection(JdbcConnection connection);
// Get logical connection
public Connection getConnection() throws SQLException;
// Close physical connection
public void close() throws SQLException;
// Event listeners
public void addConnectionEventListener(ConnectionEventListener listener);
public void removeConnectionEventListener(ConnectionEventListener listener);
// Statement event listeners
public void addStatementEventListener(StatementEventListener listener);
public void removeStatementEventListener(StatementEventListener listener);
}Usage:
// Create connection pool data source
MysqlConnectionPoolDataSource cpds = new MysqlConnectionPoolDataSource();
cpds.setURL("jdbc:mysql://localhost:3306/mydb");
cpds.setUser("root");
cpds.setPassword("password");
// Get pooled connection
PooledConnection pooledConn = cpds.getPooledConnection();
// Add connection event listener
pooledConn.addConnectionEventListener(new ConnectionEventListener() {
public void connectionClosed(ConnectionEvent event) {
System.out.println("Connection closed");
}
public void connectionErrorOccurred(ConnectionEvent event) {
System.out.println("Connection error: " + event.getSQLException());
}
});
// Get logical connection from pool
Connection conn = pooledConn.getConnection();
// Use connection...
conn.close(); // Returns to pool
// Close physical connection
pooledConn.close();Support for distributed transactions using the XA protocol.
package com.mysql.cj.jdbc;
public class MysqlXADataSource extends MysqlConnectionPoolDataSource
implements javax.sql.XADataSource {
// XA connection creation
public XAConnection getXAConnection() throws SQLException;
public XAConnection getXAConnection(String user, String password) throws SQLException;
}
public class MysqlXAConnection extends MysqlPooledConnection implements javax.sql.XAConnection {
// Constructor
public MysqlXAConnection(JdbcConnection connection, boolean logXaCommands);
// Get XA resource
public XAResource getXAResource() throws SQLException;
}
public class SuspendableXAConnection extends MysqlXAConnection {
// Constructor
public SuspendableXAConnection(JdbcConnection connection);
// XA resource with suspend/resume support
public XAResource getXAResource() throws SQLException;
}
public class MysqlXid implements javax.transaction.xa.Xid {
// Constructor
public MysqlXid(byte[] globalTransactionId, byte[] branchQualifier, int formatId);
// Xid components
public byte[] getGlobalTransactionId();
public byte[] getBranchQualifier();
public int getFormatId();
}Usage:
// Create XA data source
MysqlXADataSource xads = new MysqlXADataSource();
xads.setURL("jdbc:mysql://localhost:3306/mydb");
xads.setUser("root");
xads.setPassword("password");
// Get XA connection
XAConnection xaConn = xads.getXAConnection();
XAResource xaRes = xaConn.getXAResource();
// Create XID for transaction
Xid xid = new MysqlXid(
"global-tx-1".getBytes(),
"branch-1".getBytes(),
1
);
try {
// Start XA transaction
xaRes.start(xid, XAResource.TMNOFLAGS);
// Get connection and perform work
Connection conn = xaConn.getConnection();
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO accounts (name, balance) VALUES ('Alice', 1000)");
stmt.close();
// End XA transaction
xaRes.end(xid, XAResource.TMSUCCESS);
// Prepare phase
int prepareResult = xaRes.prepare(xid);
if (prepareResult == XAResource.XA_OK) {
// Commit phase
xaRes.commit(xid, false);
System.out.println("Transaction committed");
}
} catch (XAException e) {
// Rollback on error
try {
xaRes.rollback(xid);
} catch (XAException rollbackEx) {
rollbackEx.printStackTrace();
}
e.printStackTrace();
} finally {
xaConn.close();
}Efficient batch execution of multiple SQL statements.
// Batch operations are part of Statement interfaces
// Statement batch operations
public interface Statement {
void addBatch(String sql) throws SQLException;
void clearBatch() throws SQLException;
int[] executeBatch() throws SQLException;
long[] executeLargeBatch() throws SQLException;
}
// PreparedStatement batch operations
public interface PreparedStatement extends Statement {
void addBatch() throws SQLException;
// Inherits executeBatch() and clearBatch() from Statement
}Usage:
// Statement batch
Statement stmt = conn.createStatement();
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Alice', 25)");
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Bob', 30)");
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Charlie', 35)");
int[] updateCounts = stmt.executeBatch();
System.out.println("Batch executed: " + updateCounts.length + " statements");
// PreparedStatement batch
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "David");
pstmt.setInt(2, 28);
pstmt.addBatch();
pstmt.setString(1, "Eve");
pstmt.setInt(2, 32);
pstmt.addBatch();
pstmt.setString(1, "Frank");
pstmt.setInt(2, 27);
pstmt.addBatch();
int[] batchResults = pstmt.executeBatch();
System.out.println("Inserted " + batchResults.length + " rows");
// Enable rewriteBatchedStatements for better performance
// Set in connection URL: ?rewriteBatchedStatements=trueServer-side prepared statements for enhanced performance with repeated executions.
package com.mysql.cj.jdbc;
public class ServerPreparedStatement extends ClientPreparedStatement {
// Server-side prepared statement implementation
// Inherits all PreparedStatement methods but executes on server
// Additional server-side specific behavior
// - Statement is compiled once on server
// - Parameters sent separately for each execution
// - Better performance for repeated executions
// - Uses binary protocol
}
// Connection methods for explicit server-side preparation
public interface JdbcConnection extends Connection {
PreparedStatement serverPrepareStatement(String sql) throws SQLException;
PreparedStatement serverPrepareStatement(String sql, int autoGeneratedKeys) throws SQLException;
PreparedStatement serverPrepareStatement(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException;
PreparedStatement serverPrepareStatement(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException;
PreparedStatement serverPrepareStatement(String sql, int[] autoGeneratedKeyIndexes)
throws SQLException;
PreparedStatement serverPrepareStatement(String sql, String[] autoGeneratedKeyColNames)
throws SQLException;
}Usage:
// Enable server-side prepared statements via connection property
String url = "jdbc:mysql://localhost:3306/mydb?useServerPrepStmts=true";
Connection conn = DriverManager.getConnection(url, "root", "password");
// Or explicitly create server-side prepared statement
JdbcConnection mysqlConn = conn.unwrap(JdbcConnection.class);
PreparedStatement pstmt = mysqlConn.serverPrepareStatement(
"SELECT * FROM users WHERE age > ?"
);
// Execute multiple times - benefits from server-side caching
for (int age = 18; age <= 50; age += 10) {
pstmt.setInt(1, age);
ResultSet rs = pstmt.executeQuery();
// Process results...
rs.close();
}
pstmt.close();
// Configure prepared statement cache
// Set in URL: ?cachePrepStmts=true&prepStmtCacheSize=250&prepStmtCacheSqlLimit=2048Wrapper classes for pooled connection statement management.
package com.mysql.cj.jdbc;
public class StatementWrapper implements Statement {
// Wraps statements for pooled connections
// Delegates all calls to underlying statement
// Tracks lifecycle for proper cleanup
protected Statement wrappedStmt;
protected ConnectionWrapper connectionWrapper;
public StatementWrapper(ConnectionWrapper c, MysqlPooledConnection conn, Statement toWrap);
// All Statement methods delegated to wrappedStmt
// Close notifications sent to connection wrapper
}
public class PreparedStatementWrapper extends StatementWrapper implements PreparedStatement {
// Wraps prepared statements for pooled connections
protected PreparedStatement wrappedPrepStmt;
public PreparedStatementWrapper(ConnectionWrapper c, MysqlPooledConnection conn,
PreparedStatement toWrap);
// All PreparedStatement methods delegated to wrappedPrepStmt
}
public class CallableStatementWrapper extends PreparedStatementWrapper
implements CallableStatement {
// Wraps callable statements for pooled connections
protected CallableStatement wrappedCallableStmt;
public CallableStatementWrapper(ConnectionWrapper c, MysqlPooledConnection conn,
CallableStatement toWrap);
// All CallableStatement methods delegated to wrappedCallableStmt
}
public class ConnectionWrapper implements JdbcConnection {
// Wraps connections for pooled connection management
protected JdbcConnection wrappedConnection;
protected MysqlPooledConnection pooledConnection;
public ConnectionWrapper(MysqlPooledConnection pooledConnection, JdbcConnection connection);
// All Connection methods delegated to wrappedConnection
// Statement creation returns wrapped statements
// Close notifications sent to pooled connection
}Automatic cleanup of connections that are not properly closed.
package com.mysql.cj.jdbc;
public class AbandonedConnectionCleanupThread extends Thread {
// Singleton thread for cleaning up abandoned connections
// Check if cleanup thread is running
public static boolean isAlive();
// Manually trigger cleanup (normally automatic)
public static void checkedShutdown();
// Shutdown cleanup thread
public static void uncheckedShutdown();
}Usage:
// The cleanup thread is automatically started when needed
// and runs in the background
// To explicitly shutdown (e.g., in web application context listener):
public class MyContextListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent event) {
try {
AbandonedConnectionCleanupThread.checkedShutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}Factory for creating different types of result sets.
package com.mysql.cj.jdbc.result;
public class ResultSetFactory {
// Create result set from result data
public static ResultSet createFromResultsetRows(
int resultSetType,
int resultSetConcurrency,
ResultsetRows rows,
JdbcConnection conn,
StatementImpl stmt
) throws SQLException;
// Result set type constants (from java.sql.ResultSet)
// TYPE_FORWARD_ONLY - cursor can only move forward
// TYPE_SCROLL_INSENSITIVE - scrollable, not sensitive to changes
// TYPE_SCROLL_SENSITIVE - scrollable, sensitive to changes
// Result set concurrency constants
// CONCUR_READ_ONLY - read-only result set
// CONCUR_UPDATABLE - updatable result set
}Interface to allow PreparedStatement implementations to expose their parameter bindings to QueryInterceptors.
package com.mysql.cj.jdbc;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.sql.Array;
import java.sql.Clob;
import java.sql.Date;
import java.sql.Ref;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
/**
* Interface to allow PreparedStatement implementations to expose their parameter bindings to QueryInterceptors.
*/
public interface ParameterBindings {
Array getArray(int parameterIndex) throws SQLException;
InputStream getAsciiStream(int parameterIndex) throws SQLException;
BigDecimal getBigDecimal(int parameterIndex) throws SQLException;
InputStream getBinaryStream(int parameterIndex) throws SQLException;
java.sql.Blob getBlob(int parameterIndex) throws SQLException;
boolean getBoolean(int parameterIndex) throws SQLException;
byte getByte(int parameterIndex) throws SQLException;
byte[] getBytes(int parameterIndex) throws SQLException;
Reader getCharacterStream(int parameterIndex) throws SQLException;
Clob getClob(int parameterIndex) throws SQLException;
Date getDate(int parameterIndex) throws SQLException;
double getDouble(int parameterIndex) throws SQLException;
float getFloat(int parameterIndex) throws SQLException;
int getInt(int parameterIndex) throws SQLException;
BigInteger getBigInteger(int parameterIndex) throws SQLException;
long getLong(int parameterIndex) throws SQLException;
Reader getNCharacterStream(int parameterIndex) throws SQLException;
Reader getNClob(int parameterIndex) throws SQLException;
Object getObject(int parameterIndex) throws SQLException;
Ref getRef(int parameterIndex) throws SQLException;
short getShort(int parameterIndex) throws SQLException;
String getString(int parameterIndex) throws SQLException;
Time getTime(int parameterIndex) throws SQLException;
Timestamp getTimestamp(int parameterIndex) throws SQLException;
URL getURL(int parameterIndex) throws SQLException;
boolean isNull(int parameterIndex) throws SQLException;
}Support for streaming large result sets without loading all data into memory.
package com.mysql.cj.jdbc;
public interface JdbcStatement extends Statement {
// Enable streaming results (one row at a time)
void enableStreamingResults() throws SQLException;
// Disable streaming results (default behavior)
void disableStreamingResults() throws SQLException;
}Usage:
// Method 1: Use Statement.setFetchSize(Integer.MIN_VALUE)
Statement stmt = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY
);
stmt.setFetchSize(Integer.MIN_VALUE);
ResultSet rs = stmt.executeQuery("SELECT * FROM large_table");
while (rs.next()) {
// Process one row at a time
// Memory usage remains constant
}
// Method 2: Use enableStreamingResults()
JdbcStatement mysqlStmt = stmt.unwrap(JdbcStatement.class);
mysqlStmt.enableStreamingResults();
ResultSet rs2 = mysqlStmt.executeQuery("SELECT * FROM another_large_table");
while (rs2.next()) {
// Process streaming results
}
// Important: Only one streaming result set can be open per connection
// Close result set before executing another query
rs.close();
stmt.close();Support for update counts exceeding Integer.MAX_VALUE.
package com.mysql.cj.jdbc;
public interface JdbcStatement extends Statement {
// Execute with large update count
long executeLargeUpdate(String sql) throws SQLException;
long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException;
long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException;
long executeLargeUpdate(String sql, String[] columnNames) throws SQLException;
// Get large update count
long getLargeUpdateCount() throws SQLException;
// Large batch execution
long[] executeLargeBatch() throws SQLException;
// Large max rows
void setLargeMaxRows(long max) throws SQLException;
long getLargeMaxRows() throws SQLException;
}
public interface JdbcPreparedStatement extends PreparedStatement {
// Execute with large update count
long executeLargeUpdate() throws SQLException;
}Usage:
Statement stmt = conn.createStatement();
// Execute update returning large count
long rowsAffected = stmt.executeLargeUpdate(
"DELETE FROM logs WHERE timestamp < '2020-01-01'"
);
System.out.println("Deleted " + rowsAffected + " rows");
// Large batch execution
stmt.addBatch("UPDATE table1 SET col = 'value'");
stmt.addBatch("UPDATE table2 SET col = 'value'");
long[] largeCounts = stmt.executeLargeBatch();
// Set large max rows
stmt.setLargeMaxRows(10_000_000_000L);
long maxRows = stmt.getLargeMaxRows();Support for LOAD DATA LOCAL INFILE operations.
package com.mysql.cj.jdbc;
public interface JdbcStatement extends Statement {
// Set input stream for LOCAL INFILE
void setLocalInfileInputStream(InputStream stream);
// Get input stream for LOCAL INFILE
InputStream getLocalInfileInputStream();
}Usage:
// Enable LOCAL INFILE in connection
String url = "jdbc:mysql://localhost:3306/mydb?allowLoadLocalInfile=true";
Connection conn = DriverManager.getConnection(url, "root", "password");
Statement stmt = conn.createStatement();
JdbcStatement mysqlStmt = stmt.unwrap(JdbcStatement.class);
// Provide input stream for LOAD DATA LOCAL INFILE
InputStream fileInput = new FileInputStream("data.csv");
mysqlStmt.setLocalInfileInputStream(fileInput);
// Execute LOAD DATA LOCAL INFILE
stmt.execute(
"LOAD DATA LOCAL INFILE 'data.csv' INTO TABLE mytable " +
"FIELDS TERMINATED BY ',' " +
"LINES TERMINATED BY '\\n'"
);
fileInput.close();
stmt.close();Configuration properties specific to JDBC implementation.
package com.mysql.cj.jdbc;
public interface JdbcPropertySet extends com.mysql.cj.conf.PropertySet {
// Expose all connection properties as DriverPropertyInfo
DriverPropertyInfo[] exposeAsProperties(Properties info) throws SQLException;
}
public class JdbcPropertySetImpl implements JdbcPropertySet {
// Implementation of JDBC property set
public JdbcPropertySetImpl();
public void initializeProperties(Properties props);
public DriverPropertyInfo[] exposeAsProperties(Properties info) throws SQLException;
}Utility functions for administrative operations.
package com.mysql.cj.jdbc.admin;
public class MiniAdmin {
// Constructor
public MiniAdmin(String jdbcUrl) throws SQLException;
public MiniAdmin(String jdbcUrl, Properties props) throws SQLException;
// Shutdown MySQL server
public void shutdown() throws SQLException;
}Usage:
// Create admin instance
MiniAdmin admin = new MiniAdmin("jdbc:mysql://localhost:3306/");
// Shutdown MySQL server
admin.shutdown();Connection tester for C3P0 connection pool integration.
package com.mysql.cj.jdbc.integration.c3p0;
public class MysqlConnectionTester implements com.mchange.v2.c3p0.ConnectionTester {
// Test connection liveness using COM_PING
public int activeCheckConnection(Connection c);
// Test connection on checkout
public int statusOnException(Connection c, Throwable t);
}Usage with C3P0:
// Configure C3P0 data source with MySQL connection tester
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
cpds.setUser("root");
cpds.setPassword("password");
// Use MySQL-specific connection tester
cpds.setConnectionTesterClassName(
"com.mysql.cj.jdbc.integration.c3p0.MysqlConnectionTester"
);
// Pool configuration
cpds.setMinPoolSize(5);
cpds.setMaxPoolSize(20);
cpds.setAcquireIncrement(5);
cpds.setTestConnectionOnCheckout(true);
Connection conn = cpds.getConnection();Helper for iterating over result sets.
package com.mysql.cj.jdbc;
public abstract class IterateBlock<T> {
// Constructor
public IterateBlock();
// Override this method to process each row
public abstract void forEach(T each) throws SQLException;
// Execute iteration
public final void doForAll(Iterator<T> iterator) throws SQLException;
}Usage:
// Custom iteration logic
IterateBlock<Row> rowProcessor = new IterateBlock<Row>() {
@Override
public void forEach(Row row) throws SQLException {
// Process each row
System.out.println("Processing row: " + row);
}
};
// Execute iteration
// rowProcessor.doForAll(rowIterator);Enumeration for connection close options.
package com.mysql.cj.jdbc;
public enum CloseOption {
IMPLICIT, // Close operation initiated internally by a clean up routine
FORCED, // A forced, hard close
ROLLBACK, // Allow rollback during the close operation
PROPAGATE, // Allow propagating the close operation to dependents and owner objects
NO_CACHE; // Does not allow caching the closing object
public boolean in(CloseOption... options);
public boolean notIn(CloseOption... options);
}Support for changing the authenticated user on an existing connection.
package com.mysql.cj.jdbc;
public interface JdbcConnection extends Connection {
// Change authenticated user
void changeUser(String userName, String newPassword) throws SQLException;
}Usage:
Connection conn = DriverManager.getConnection(url, "user1", "pass1");
// Change to different user
JdbcConnection mysqlConn = conn.unwrap(JdbcConnection.class);
mysqlConn.changeUser("user2", "pass2");
// Connection now authenticated as user2Install with Tessl CLI
npx tessl i tessl/maven-com-mysql--mysql-connector-j