前面已经知道了对于JDBC4.0,java.sql.Connection的网络服务器和嵌入式的实现类分别为NetConnection40和EmbedConnection40。
下面就以就以嵌入式方式为例来说明下ResultSet的获取过程。
一个一般的调用过程应该是如下这样的,
可以在EmbedConnection40的父类org.apache.derby.impl.jdbc.EmbedConnection找到#createStatement()的实现
下面要看一下newEmbedStatement()的实现,对于JDBC4.0,要去org.apache.derby.jdbc.Driver40找这个方法的实现,
这里可以看到Statement的实现是org.apache.derby.impl.jdbc.EmbedStatement40。在它的父类EmbedStatement中定义了executeQuery()方法,
这里要首先看一下lcc这个实例对应的org.apache.derby.iapi.sql.conn.LanguageConnectionContext类的作用。
首先lcc的实例化是在EmbedStatement的构造函数中进行的,
可以在EmbedConnection中找到这个方法#getLanguageConnection()方法,它是final的
这里有一个getTR()方法,返回了一个final的类TransactionResourceImpl,看这个类的JavaDoc,它负责的事情还是很多的,比如与数据库的连接,事务的上下文等,在TransactionResourceImpl中可以通过getLcc()方法得到LanguageConnectionContext实例。
这里lcc实例是在startTransaction()方法中初始化的,
这里有2个地方还不清楚,一个是#startTransaction()方法是何时调用的,另外一个是database是什么时候初始化的,要了解这个问题首先要看一下TransactionResourceImpl的构造函数,然后还要看一下EmbedConnection的构造函数
在TransactionResourceImpl的构造函数里,对ContextService(csf)和ContextManager(cm)进行了初始化。
然后看一下EmbedConnection的构造函数,这个比较长,中间略过了一部分。
这里,在EmbedConnection的构造函数中其实已经完成了很多的工作,比如TransactionResourceImpl(tr)的初始化,database的创建和启用等,这个构造方法其实还有很多需要研究的地方,下面来逐个的研究下。
下面就以就以嵌入式方式为例来说明下ResultSet的获取过程。
一个一般的调用过程应该是如下这样的,
Connection conn = DriverManager.getConnection(url, "username", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from table");
while(rs.next()){
......
}
可以在EmbedConnection40的父类org.apache.derby.impl.jdbc.EmbedConnection找到#createStatement()的实现
public final Statement createStatement() throws SQLException {
return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connectionHoldAbility);
}
public final Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
checkIfClosed();
/* 这里的factory究竟是哪个类的实例可以看一下前面Connection获取的部分,对于JDBC4.0就是Driver40的实例 */
return factory.newEmbedStatement(this, false, setResultSetType(resultSetType), resultSetConcurrency,
resultSetHoldability);
}
下面要看一下newEmbedStatement()的实现,对于JDBC4.0,要去org.apache.derby.jdbc.Driver40找这个方法的实现,
public java.sql.Statement newEmbedStatement(EmbedConnection conn, boolean forMetaData, int resultSetType,
int resultSetConcurrency, int resultSetHoldability) {
return new EmbedStatement40(conn, forMetaData, resultSetType, resultSetConcurrency, resultSetHoldability);
}
这里可以看到Statement的实现是org.apache.derby.impl.jdbc.EmbedStatement40。在它的父类EmbedStatement中定义了executeQuery()方法,
public java.sql.ResultSet executeQuery(String sql) throws SQLException {
execute(sql, true, false, Statement.NO_GENERATED_KEYS, null, null);
if (SanityManager.DEBUG) {
if (results == null)
SanityManager.THROWASSERT("no results returned on executeQuery()");
}
return results;
}
private boolean execute(String sql, boolean executeQuery, boolean executeUpdate, int autoGeneratedKeys,
int[] columnIndexes, String[] columnNames) throws SQLException {
synchronized (getConnectionSynchronization()) {
checkExecStatus();
if (sql == null) {
throw newSQLException(SQLState.NULL_SQL_TEXT);
}
checkIfInMiddleOfBatch();
/* 关闭与这个Statement关联的ResultSet */
clearResultSets();
setupContextStack();
SQLText = sql;
try {
/* 获取Activation对象 */
Activation activation;
try {
PreparedStatement preparedStatement = lcc.prepareInternalStatement(lcc.getDefaultSchema(), sql,
resultSetConcurrency == java.sql.ResultSet.CONCUR_READ_ONLY, false);
activation = preparedStatement.getActivation(lcc,
resultSetType == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE);
checkRequiresCallableStatement(activation);
} catch (Throwable t) {
throw handleException(t);
}
activation.setSingleExecution();
if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS)
activation.setAutoGeneratedKeysResultsetInfo(columnIndexes, columnNames);
/* 执行Statement */
return executeStatement(activation, executeQuery, executeUpdate);
} finally {
restoreContextStack();
}
}
}
这里要首先看一下lcc这个实例对应的org.apache.derby.iapi.sql.conn.LanguageConnectionContext类的作用。
首先lcc的实例化是在EmbedStatement的构造函数中进行的,
public EmbedStatement(EmbedConnection connection, boolean forMetaData, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) {
super(connection);
this.forMetaData = forMetaData;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
this.resultSetHoldability = resultSetHoldability;
/* 这里就是lcc的初始化了 */
lcc = getEmbedConnection().getLanguageConnection();
applicationConnection = getEmbedConnection().getApplicationConnection();
applicationStatement = this;
}
可以在EmbedConnection中找到这个方法#getLanguageConnection()方法,它是final的
public final LanguageConnectionContext getLanguageConnection() {
if (SanityManager.DEBUG)
SanityManager.ASSERT(!isClosed(), "connection is closed");
return getTR().getLcc();
}
这里有一个getTR()方法,返回了一个final的类TransactionResourceImpl,看这个类的JavaDoc,它负责的事情还是很多的,比如与数据库的连接,事务的上下文等,在TransactionResourceImpl中可以通过getLcc()方法得到LanguageConnectionContext实例。
LanguageConnectionContext getLcc() {
return lcc;
}
这里lcc实例是在startTransaction()方法中初始化的,
void startTransaction() throws StandardException, SQLException {
lcc = database.setupConnection(cm, username, drdaID, dbname);
}
这里有2个地方还不清楚,一个是#startTransaction()方法是何时调用的,另外一个是database是什么时候初始化的,要了解这个问题首先要看一下TransactionResourceImpl的构造函数,然后还要看一下EmbedConnection的构造函数
TransactionResourceImpl(InternalDriver driver, String url, Properties info) throws SQLException {
/* 对于JDBC4.0这里driver是Driver40类的实例 */
this.driver = driver;
/* csf是一个org.apache.derby.iapi.services.context.ContextService的实例 */
/* ContextService是一个访问上下文的工具方法类 */
csf = driver.getContextServiceFactory();
dbname = InternalDriver.getDatabaseName(url, info);
this.url = url;
username = IdUtil.getUserNameFromURLProps(info);
drdaID = info.getProperty(Attribute.DRDAID_ATTR, null);
// ContextManager对象,这里ContextManager还要push一个org.apache.derby.iapi.services.context.SystemContext到ContextManager中
cm = csf.newContextManager();
}
在TransactionResourceImpl的构造函数里,对ContextService(csf)和ContextManager(cm)进行了初始化。
然后看一下EmbedConnection的构造函数,这个比较长,中间略过了一部分。
public EmbedConnection(InternalDriver driver, String url, Properties info) throws SQLException {
// rootConnection
applicationConnection = rootConnection = this;
// 对于JDBC4.0这里driver是Driver40类的实例
factory = driver;
// 这里初始化了TransactionResourceImpl
tr = new TransactionResourceImpl(driver, url, info);
active = true;
// 将ContextManager设为ContextService的当前Manager
setupContextStack();
try {
// 初始化一个EmbedConnectionContext实例,并且push这个Context到ContextManager中
EmbedConnectionContext context = pushConnectionContext(tr.getContextManager());
boolean shutdown = Boolean.valueOf(info.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue();
// 查看database模块是否启动了,在modules.properties中定义的是org.apache.derby.impl.db.BasicDatabase
Database database = (Database) Monitor.findService(Property.DATABASE_MODULE, tr.getDBName());
// 查看是否用户想创建一个新的数据库
boolean createBoot = createBoot(info);
boolean isTwoPhaseEncryptionBoot = (!createBoot && isEncryptionBoot(info));
boolean isTwoPhaseUpgradeBoot = (!createBoot && isHardUpgradeBoot(info));
/* 如果数据库连接的属性中包括"startSlave",那么是使用了Replication slave模式 */
/* 这部分关于Master-Slave的内容我也没有研究 */
boolean isStartSlaveBoot = isStartReplicationSlaveBoot(info);
boolean slaveDBAlreadyBooted = false;
boolean isFailoverMasterBoot = false;
boolean isFailoverSlaveBoot = false;
......
......
if (database != null) {// database已经启动了
tr.setDatabase(database);
isTwoPhaseEncryptionBoot = false;
isTwoPhaseUpgradeBoot = false;
} else if (!shutdown) {
if (isTwoPhaseEncryptionBoot || isTwoPhaseUpgradeBoot) {
savedInfo = info;
info = removePhaseTwoProps((Properties) info.clone());
}
if (!bootDatabase(info, isTwoPhaseUpgradeBoot)) {
tr.clearContextInError();
setInactive();
return;
}
}
if (createBoot && !shutdown) {// 如果要创建一个新的database
if (tr.getDatabase() != null) {
// database已经存在
addWarning(SQLWarningFactory.newSQLWarning(SQLState.DATABASE_EXISTS, getDBName()));
} else {
checkUserCredentials(null, info);
// 创建一个新的
database = createDatabase(tr.getDBName(), info);
/*这里将database设定到了TransactionResourceImpl*/
tr.setDatabase(database);
}
}
if (tr.getDatabase() == null) {// database没有启动
handleDBNotFound();
}
try {
//看看这个用户是否合法
checkUserCredentials(tr.getDBName(), info);
} catch (SQLException sqle) {
if (isStartSlaveBoot && !slaveDBAlreadyBooted) {
tr.startTransaction();
handleException(tr.shutdownDatabaseException());
}
throw sqle;
}
// 这里就是lcc实例的获取了,这个方法后边还要仔细看
tr.startTransaction();
......
......
} catch (OutOfMemoryError noMemory) {
restoreContextStack();
tr.lcc = null;
tr.cm = null;
memoryState.setLowMemory();
throw NO_MEM;
} catch (Throwable t) {
if (t instanceof StandardException) {
StandardException se = (StandardException) t;
if (se.getSeverity() < ExceptionSeverity.SESSION_SEVERITY)
se.setSeverity(ExceptionSeverity.SESSION_SEVERITY);
}
tr.cleanupOnError(t);
throw handleException(t);
} finally {
restoreContextStack();
}
}
这里,在EmbedConnection的构造函数中其实已经完成了很多的工作,比如TransactionResourceImpl(tr)的初始化,database的创建和启用等,这个构造方法其实还有很多需要研究的地方,下面来逐个的研究下。