Derby源代码分析 -- JDBC实现(三)

在开始下面的分析前,先补一下课,插播下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到cm
pushDbContext(cm);

// 返回一个GenericLanguageConnectionContext实例,并且push到cm
LanguageConnectionContext lctx = lcf.newLanguageConnectionContext(cm, tc, lf, this, user, drdaID, dbname);

// push ClassFactory到cm
pushClassFactoryContext(cm, lcf.getClassFactory());

ExecutionFactory ef = lcf.getExecutionFactory();

// push ExecutionContext到cm
ef.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都为true
commitIfNeeded();
// 把needCommit置为true
needCommit();
} else {

if (lcc.getActivationCount() > 1) {
} else {
commitIfNeeded(); // we can legitimately commit
needCommit();
}
}

// 返回SQL层的PreparedStatement
PreparedStatement 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的ResultSet
EmbedResultSet 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 more

if (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层是如何实现的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值