Derby源代码分析 -
在开始下面的分析前,先补一下课,插播下Derby的代码结构,Derby主要是分四个部分来组织代码的:JDBC, SQL, Store and Services。
JDBC层处于最顶端,是与应用程序进行交互的部分。JDBC的下面是SQL层,SQL层主要是负责编译和执行这两种工作,生成SQL执行计划并返回执行结果。再向下的一层是Store层,主要负责访问数据和存储。最后是Service,顾名思义,就是一些服务的module了。这个的原文在http://db.apache.org/derby/papers/derby_arch.html,可以自己去了解下。
所以,我们这部分的解析主要是了解JDBC层的东西,里边也会涉及一些SQL层的代码。SQL层的类很多会和JDBC层有同一个名字,比如Statement,不过是Derby的实现罢了。
大致了解了Derby的代码结构之后,我们就来继续前面的分析,首先来看一下Database的创建,就是EmbedConnection的createDatabase()方法。
private Database createDatabase(String dbname, Properties info) throws SQLException {info = filterProperties(info);try {// 创建持久化服务if (Monitor.createPersistentService(Property.DATABASE_MODULE, dbname, info) == null) {addWarning(SQLWarningFactory.newSQLWarning(SQLState.DATABASE_EXISTS, dbname));}} catch (StandardException mse) {throw Util.seeNextException(SQLState.CREATE_DATABASE_FAILED, new Object[] { dbname }, handleException(mse));}info.clear();return (Database) Monitor.findService(Property.DATABASE_MODULE, dbname);}
接着是Monitor的#createPersistentService()
public static Object createPersistentService(String factoryInterface, String serviceName, Properties properties)throws StandardException {if (SanityManager.DEBUG) {SanityManager.ASSERT(factoryInterface != null, "serviceName is null");SanityManager.ASSERT(serviceName != null, "serviceName is null");}// 这里的monitor对应的是BaseMonitor的实例return monitor.createPersistentService(factoryInterface, serviceName, properties);}
最后是BaseMonitor的#createPersistentService()
public Object createPersistentService(String factoryInterface, String name, Properties properties)throws StandardException {PersistentService provider = findProviderForCreate(name);if (provider == null) {throw StandardException.newException(SQLState.PROTOCOL_UNKNOWN, name);}// 这里就要启动名字是"name"的database模块了,这里的"name"是在数据库连接URL中写明的return bootService(provider, factoryInterface, name, properties, true);}
如果你还记得我前面服务器启动部分的分析,这里的bootService()方法会启动一个Module,名字是"name"对应的字符串,在这里就是客户端请求的数据库名。
而factoryInterface是"org.apache.derby.database.Database"对应的实现,可以在modules.properties中找到它的默认实现类是org.apache.derby.impl.db.BasicDatabase。这里还有一个org.apache.derby.impl.db.SlaveDatabase的实现,它是用于replication slave模式的,现在先不考虑。
启动过程中,要调用BasicDatabase的#boot()方法,boot方法主要是一系列服务的启动,这里就不列出代码了。
要了解的第二个是lcc(lcc属于SQL层)实例的获取,就是tr.startTransaction();这步调用,
void startTransaction() throws StandardException, SQLException {lcc = database.setupConnection(cm, username, drdaID, dbname);}
这里和前面说的database是有关系的,来看一下BasicDatabase的实现
public LanguageConnectionContext setupConnection(ContextManager cm, String user, String drdaID, String dbname)throws StandardException {TransactionController tc = getConnectionTransaction(cm);cm.setLocaleFinder(this);// push DatabaseContext到cmpushDbContext(cm);// 返回一个GenericLanguageConnectionContext实例,并且push到cmLanguageConnectionContext lctx = lcf.newLanguageConnectionContext(cm, tc, lf, this, user, drdaID, dbname);// push ClassFactory到cmpushClassFactoryContext(cm, lcf.getClassFactory());ExecutionFactory ef = lcf.getExecutionFactory();// push ExecutionContext到cmef.newExecutionContext(cm);lctx.initialize();lctx.internalCommitNoSync(TransactionController.RELEASE_LOCKS | TransactionController.READONLY_TRANSACTION_INITIALIZATION);return lctx;}
这样lcc就初始化完成了。
这里简单的总结一下,EmbedConnection的构造函数是做了很多东西的,首先是Database模块的启动(如果已经启动返回模块引用),然后是创建JDBC层与SQL层的接口lcc,实现了层之间的互联。
下面还是回到EmbedStatement的execute()方法来继续分析下ResultSet的获取,
/* 获取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);
这里lcc已经知道了是GenericLanguageConnectionContext的实例了,这个类是属于SQL层的。根据GenericLanguageConnectionContext的JavaDoc,LanguageConnectionContext维护了一个PreparedStatement、activation和cursor的实例池,这里的PreparedStatement是Derby SQL层的实现,并不是JDBC的。
暂时这里的Activation和PreparedStatement的获得就不再进一步讨论了,因为我查看源代码时发现里边涉及到了太多的SQL层细节,这里就先不去深究了。还是把目光转回JDBC层,看一下executeStatement(activation, executeQuery, executeUpdate);这句
boolean executeStatement(Activation a, boolean executeQuery, boolean executeUpdate) throws SQLException {synchronized (getConnectionSynchronization()) {if (SanityManager.DEBUG) {SanityManager.ASSERT(results == null);SanityManager.ASSERT(dynamicResults == null);SanityManager.ASSERT(autoGeneratedKeysResultSet == null);}// 确保创建上下文setupContextStack();boolean retval;pvs = a.getParameterValueSet();try {// 清掉警告clearWarnings();if (!forMetaData) {// 如果需要的话,提交上次的Statement// 这里要autoCommit和needCommit都为truecommitIfNeeded();// 把needCommit置为trueneedCommit();} else {if (lcc.getActivationCount() > 1) {} else {commitIfNeeded(); // we can legitimately commitneedCommit();}}// 返回SQL层的PreparedStatementPreparedStatement ps = a.getPreparedStatement();ps.rePrepare(lcc);// 加入编译警告addWarning(ps.getCompileTimeWarnings());// 设定Cursor,看JavaDoc说的是JDBC要求把select statement转变成Cursor,具体我也不是很明白if (cursorName != null) {a.setCursorName(cursorName);}// 设定结果集持久性,就是当事务提交的之后是否ResultSet还要继续打开boolean executeHoldable = getExecuteHoldable();a.setResultSetHoldability(executeHoldable);a.reset();a.setMaxRows(maxRows);// 这里的ResultSet也是SQL层的实现,不是JDBC的,这里的#execute()方法很重要,不过JDBC层就不讨论了ResultSet resultsToWrap = ps.execute(a, timeoutMillis);addWarning(a.getWarnings());if (resultsToWrap.returnsRows()) {// 是否返回结果if (executeUpdate) {throw StandardException.newException(SQLState.LANG_INVALID_CALL_TO_EXECUTE_UPDATE);}// 生成JDBC的ResultSetEmbedResultSet lresults = factory.newEmbedResultSet(getEmbedConnection(), resultsToWrap,forMetaData, this, ps.isAtomic());results = lresults;if (a.isSingleExecution())lresults.singleUseActivation = a;updateCount = -1;retval = true;} else {// 不用返回结果if (a.getAutoGeneratedKeysResultsetMode()&& (resultsToWrap.getAutoGeneratedKeysResultset() != null)) {resultsToWrap.getAutoGeneratedKeysResultset().open();autoGeneratedKeysResultSet = factory.newEmbedResultSet(getEmbedConnection(), resultsToWrap.getAutoGeneratedKeysResultset(), false, this, ps.isAtomic());}// 更新的行数updateCount = resultsToWrap.modifiedRowCount();results = null; // note that we have none.int dynamicResultCount = 0;if (a.getDynamicResults() != null) {dynamicResultCount = processDynamicResults(a.getDynamicResults(), a.getMaxDynamicResults());}resultsToWrap.close(); // Don't need the result set any moreif (executeQuery && dynamicResultCount != 1) {throw StandardException.newException(SQLState.LANG_INVALID_CALL_TO_EXECUTE_QUERY);}if (executeUpdate && dynamicResultCount > 0) {throw StandardException.newException(SQLState.LANG_INVALID_CALL_TO_EXECUTE_UPDATE);}if (dynamicResultCount == 0) {if (a.isSingleExecution()) {a.close();}if (!forMetaData)commitIfNeeded();else {if (lcc.getActivationCount() > 1) {} else {commitIfNeeded(); // we can legitimately commit}}}retval = (dynamicResultCount > 0);}} catch (Throwable t) {if (a.isSingleExecution()) {try {a.close();} catch (Throwable tt) {;}}throw handleException(t);} finally {restoreContextStack();}return retval;}}
这样,大致的SQL运行过程在JDBC层的运行流程就大致讲完了。后边才是更深入的方面,就是SQL运行在SQL层是如何实现的。
页:
[1]