getConnection
java语句如下:
cn = DriverManager.getConnection(
"jdbc:mysql://100.83.94.89:3306/mysql?user=root&password=mysql&useEncryption=true");
mysql jdbc代码里没有DriverManager类,这个可能是java自己的类。也没有getConnection的实现(其实有getConnection的实现,但是都不是DriverManager类的,不是上面代码里用到的getConnection)。
getConnection会调用具体某个jdbc驱动的connect方法,在这里就是mysql jdbc驱动的connect方法。所以java代码在DriverManager.getConnection的前面会有一句load jdbc的语句。
Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
mysql jdbc被调用的真正入口是connect方法,详见这篇文章(DriverManager.getConnection()方法涉及到的源码详解-CSDN博客)
mysql jdbc的connect代码可能是在这里:
public java.sql.Connection connect(String url, Properties info) throws SQLException {
try {
if (!ConnectionUrl.acceptsUrl(url)) {
/*
* According to JDBC spec:
* The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the
* JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.
*/
return null;
}
ConnectionUrl conStr = ConnectionUrl.getConnectionUrlInstance(url, info);
switch (conStr.getType()) {
case SINGLE_CONNECTION:
return com.mysql.cj.jdbc.ConnectionImpl.getInstance(conStr.getMainHost());
case FAILOVER_CONNECTION:
case FAILOVER_DNS_SRV_CONNECTION:
return FailoverConnectionProxy.createProxyInstance(conStr);
case LOADBALANCE_CONNECTION:
case LOADBALANCE_DNS_SRV_CONNECTION:
return LoadBalancedConnectionProxy.createProxyInstance(conStr);
case REPLICATION_CONNECTION:
case REPLICATION_DNS_SRV_CONNECTION:
return ReplicationConnectionProxy.createProxyInstance(conStr);
default:
return null;
}
} catch (UnsupportedConnectionStringException e) {
// when Connector/J can't handle this connection string the Driver must return null
return null;
} catch (CJException ex) {
throw ExceptionFactory.createException(UnableToConnectException.class,
Messages.getString("NonRegisteringDriver.17", new Object[] { ex.toString() }), ex);
}
}
所以,最终return的是个ConnectionImpl对象。
对象在构造函数里,设置一大堆属性之后创建了个真正的网络连接:
createNewIO(false);
unSafeQueryInterceptors();
AbandonedConnectionCleanupThread.trackConnection(this, this.getSession().getNetworkResources());
prepareStatement
prepareStatement也是ConnectionImpl的方法,不过实现很多,在ConnectionWrapper里也有实现。如果server ps打开的话返回的是ServerPreparedStatement,如果client ps的话返回clientPrepareStatement
对象。
public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
synchronized (getConnectionMutex()) {
checkClosed();
//
// FIXME: Create warnings if can't create results of the given type or concurrency
//
ClientPreparedStatement pStmt = null;
boolean canServerPrepare = true;
String nativeSql = this.processEscapeCodesForPrepStmts.getValue() ? nativeSQL(sql) : sql;
if (this.useServerPrepStmts.getValue() && this.emulateUnsupportedPstmts.getValue()) {
canServerPrepare = canHandleAsServerPreparedStatement(nativeSql);
}
if (this.useServerPrepStmts.getValue() && canServerPrepare) {
if (this.cachePrepStmts.getValue()) {
synchronized (this.serverSideStatementCache) {
pStmt = this.serverSideStatementCache.remove(new CompoundCacheKey(this.database, sql));
if (pStmt != null) {
((com.mysql.cj.jdbc.ServerPreparedStatement) pStmt).setClosed(false);
pStmt.clearParameters();
}
if (pStmt == null) {
try {
pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType,
resultSetConcurrency);
if (sql.length() < this.prepStmtCacheSqlLimit.getValue()) {
((com.mysql.cj.jdbc.ServerPreparedStatement) pStmt).isCacheable = true;
}
pStmt.setResultSetType(resultSetType);
pStmt.setResultSetConcurrency(resultSetConcurrency);
} catch (SQLException sqlEx) {
// Punt, if necessary
if (this.emulateUnsupportedPstmts.getValue()) {
pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
if (sql.length() < this.prepStmtCacheSqlLimit.getValue()) {
this.serverSideStatementCheckCache.put(sql, Boolean.FALSE);
}
} else {
throw sqlEx;
}
}
}
}
} else {
try {
pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType, resultSetConcurrency);
pStmt.setResultSetType(resultSetType);
pStmt.setResultSetConcurrency(resultSetConcurrency);
} catch (SQLException sqlEx) {
// Punt, if necessary
if (this.emulateUnsupportedPstmts.getValue()) {
pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
} else {
throw sqlEx;
}
}
}
} else {
pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
}
return pStmt;
}
}
ServerPreparedStatement对象的构造函数第一个参数事实上就是Connection对象,内部会调用serverPrepare接口执行prepare流程:
protected ServerPreparedStatement(JdbcConnection conn, String sql, String db, int resultSetType, int resultSetConcurrency) throws SQLException {
super(conn, db);
checkNullOrEmptyQuery(sql);
String statementComment = this.session.getProtocol().getQueryComment();
PreparedQuery prepQuery = (PreparedQuery) this.query;
prepQuery.setOriginalSql(statementComment == null ? sql : "/* " + statementComment + " */ " + sql);
prepQuery.setQueryInfo(new QueryInfo(prepQuery.getOriginalSql(), this.session, this.charEncoding));
this.hasOnDuplicateKeyUpdate = prepQuery.getQueryInfo().containsOnDuplicateKeyUpdate();
try {
serverPrepare(sql);
} catch (CJException | SQLException sqlEx) {
realClose(false, true);
throw SQLExceptionsMapping.translateException(sqlEx, this.exceptionInterceptor);
}
setResultSetType(resultSetType);
setResultSetConcurrency(resultSetConcurrency);
}
ServerPreparedStatement.serverPrepare又会调用ServerPreparedQuery.serverPrepare,真正的核心流程在
ServerPreparedQuery.serverPrepare里。
executeUpdate
最后应该是调用到了StatementImplement.executeUpdateInternal,真正执行的地方是:
rs = ((NativeSession) locallyScopedConn.getSession()).execSQL(this, sql, -1, null, false, getResultSetFactory(), null, isBatch);
执行之后把rs指针存进了自己的属性里:
this.results = rs;
rs.setFirstCharOfQuery(firstStatementChar);
this.updateCount = rs.getUpdateCount();
this.lastInsertId = rs.getUpdateID();
return this.updateCount;
setXXX
最后调用的在NativeQueryBindValue.setBinding方法,只是把数据存了下来。
public void setBinding(Object obj, MysqlType type, int numberOfExecutions, AtomicBoolean sendTypesToServer) {
if (sendTypesToServer != null) {
sendTypesToServer.compareAndSet(false, resetToType(type)); // specific to ServerPreparedQuery
}
this.value = obj;
this.targetType = type;
this.boundBeforeExecutionNum = numberOfExecutions;
this.isNull = this.targetType == MysqlType.NULL;
this.isSet = true;
this.escapeBytesIfNeeded = true;
Supplier<ValueEncoder> vc = this.protocol.getValueEncoderSupplier(this.isNull ? null : this.value);
if (vc != null) {
this.valueEncoder = vc.get();
this.valueEncoder.init(this.pset, this.serverSession, this.exceptionInterceptor);
} else {
throw ExceptionFactory.createException(WrongArgumentException.class,
Messages.getString("PreparedStatement.67", new Object[] { obj.getClass().getName(), type.name() }), this.exceptionInterceptor);
}
}
executeQuery
和executeUpdate类似,调用到了executeInternal里,最后调用的是execSQL获取rs。
protected <M extends Message> ResultSetInternalMethods executeInternal(int maxRowsToRetrieve, M sendPacket, boolean createStreamingResultSet,
boolean queryIsSelectOnly, ColumnDefinition metadata, boolean isBatch) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
try {
JdbcConnection locallyScopedConnection = this.connection;
((PreparedQuery) this.query).getQueryBindings()
.setNumberOfExecutions(((PreparedQuery) this.query).getQueryBindings().getNumberOfExecutions() + 1);
ResultSetInternalMethods rs;
CancelQueryTask timeoutTask = null;
try {
timeoutTask = startQueryTimer(this, getTimeoutInMillis());
if (!isBatch) {
statementBegins();
}
rs = ((NativeSession) locallyScopedConnection.getSession()).execSQL(this, null, maxRowsToRetrieve, (NativePacketPayload) sendPacket,
createStreamingResultSet, getResultSetFactory(), metadata, isBatch);
if (timeoutTask != null) {
stopQueryTimer(timeoutTask, true, true);
timeoutTask = null;
}
} finally {
if (!isBatch) {
this.query.getStatementExecuting().set(false);
}
stopQueryTimer(timeoutTask, false, false);
}
return rs;
} catch (NullPointerException npe) {
checkClosed(); // we can't synchronize ourselves against async connection-close due to deadlock issues, so this is the next best thing for
// this particular corner case.
throw npe;
}
}
}