在开始下面的分析前,先补一下课,插播下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层是如何实现的。
分享到:
相关推荐
JDBC提供了一种统一的接口,使得开发者可以轻松地切换不同的数据库系统,提高了代码的可移植性。同时,它还支持连接池、数据源等高级特性,以提升性能和管理效率。在实际开发中,理解并熟练使用这些数据库的JDBC特性...
"db-derby-10.11.1.1-src.zip" 是Apache Derby的10.11.1.1版本的源代码包,对于开发者来说,这是一个宝贵的资源,可以深入了解Derby的内部工作原理和实现细节。 Apache Derby的核心特性包括: 1. **完全用Java编写...
Apache Derby,也被称为Java DB,是一款轻量级、开源的关系型数据库管理系统,完全用Java编写,遵循Apache软件基金会的开放源代码协议。这个名为"db-derby-10.11.1.1-bin.zip"的压缩包包含了Apache Derby 10.11.1.1...
博客链接提到的"源码"可能是指查看或分析JDBC驱动的源代码,理解其内部工作原理,而"工具"可能是指使用一些辅助工具,如数据库管理工具(如SQL Developer或MySQL Workbench),或者开发工具(如IDEA的数据库插件)来...
总之,`spring-jdbc-4.2.xsd`是Spring JDBC模块配置的核心,它为Spring JDBC的配置提供了一套规范,使得开发者可以清晰、有序地设置数据库连接、数据源、事务管理等相关属性,提高了代码的可读性和可维护性。...
在开发Derby应用时,JDT用于编写和管理Java源代码,创建JDBC客户端应用程序,这些应用程序将与Derby数据库进行交互。 DB2 plug-ins for Eclipse是IBM提供的扩展,它增强了Eclipse对多种数据库(包括Apache Derby)...
2. **jTDS**:jTDS是一个开放源代码的JDBC驱动,主要针对Microsoft SQL Server和Sybase Adaptive Server Anywhere。它实现了JDBC Type 4驱动,能直接与数据库服务器通过TCP/IP通信,提供高速、稳定的数据访问。 3. ...
### 源代码检查工具SONAR使用经验 #### Sonar概述 Sonar作为一个代码质量管理的开放平台,通过灵活的插件机制集成了多种测试工具、代码分析工具以及持续集成工具。与传统持续集成工具(如Hudson/Jenkins)相比,...
在标签"源码"提及的情况下,对于开发者来说,Apache Derby的源代码是开放的,这意味着你可以查看、学习甚至贡献代码到项目中。这为理解数据库内部工作原理,调试问题,或者定制特定需求提供了可能性。 至于"工具...
1. 开源:Apache Derby遵循Apache License 2.0协议,允许用户自由地使用和分发,并可以根据自己的需求对源代码进行修改。 2. 嵌入式模式:Derby可以作为应用程序的一部分嵌入到应用中去运行,无需单独的服务器进程。...
- **方法一:使用内置Derby插件**:Eclipse有内建的Derby支持,可以通过Window > Preferences > Database Development > Drivers添加Derby驱动,然后创建数据源。 - **方法二:通过Eclipse Marketplace安装插件**...
- `src`目录:Java源代码文件,包含上述示例中的类。 - `lib`目录(可选):可能包含Apache Derby的JDBC驱动库文件(如`derby.jar`)。 - `build.xml`或`pom.xml`:构建脚本,可能是Ant或Maven,用于编译和打包项目...
在深入学习`apache-hive-1.2.2-src`源代码之前,我们首先需要了解Hive的基本概念和工作流程。 Hive的核心组件包括: 1. **元数据存储**:Hive存储关于表、列、分区等元数据,通常在MySQL或Derby数据库中。 2. **...
6. **开放源代码:**作为ASF的一个项目,Derby的源代码完全开放,这有助于开发者深入理解其内部机制,并根据自身需求进行定制和扩展。 #### 五、Derby的应用场景 由于其轻量级和易于集成的特点,Derby广泛应用于...
开发者可以查看这些源代码,学习如何利用Swing组件构建用户界面,以及如何通过Derby进行数据存储和检索。源码通常包括了类文件、资源文件以及可能的配置文件。通过阅读源码,初学者可以了解实际项目中Swing和Derby的...
源代码的提供意味着用户可以查看、学习甚至修改系统的内部实现,以适应特定需求或进行二次开发。 Swing是Java的一个图形用户界面(GUI)工具包,它是Java Foundation Classes (JFC)的一部分,用于构建桌面应用。...
5. **src目录**: 源码文件通常存放在src目录下,包括所有Java源代码文件(以.java为扩展名)。这里的源码应该是实现通讯录功能的类,比如用于显示和管理联系人的控制器类,以及可能的模型类和视图类。开发者可能会...
在Java应用程序中通过JDBC(Java Database Connectivity)连接到Oracle数据库时,主要使用以下代码: ```java Class.forName("oracle.jdbc.driver.OracleDriver"); Connection con = DriverManager.getConnection(...
1. **基本JDBC-ODBC桥接驱动**:这是一种基于ODBC的驱动,它不是纯Java实现的。 2. **部分Java驱动**:这种驱动需要本地代码与Java交互,提供了一些Java功能,但仍依赖于ODBC。 3. **网络协议纯Java驱动**:这类驱动...