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

谈起JDBC的实现,还是从获取Connection开始吧。

下面这句就是一般的获取Connection的代码了,

DriverManager.getConnection(url, "username", "password");


当每个Driver初始化的时候,都会在DriverManager中注册下自己,就是调用这个registerDriver(java.sql.Driver driver)静态方法,然后当想获得Connnection的时候DriverManager就可以通过注册的驱动来从特定的数据库获得了。如果有兴趣可以看一下JDK中DriverManager的#getConnection()的实现,这里就不再列出代码了。而这里需要说明的是在#gertConnection()方法中会调用到先前注册的Driver的#connect(String url, Properties info)方法,其中info里保存了用户名和密码。下面就从这里开始分析吧。

[size=medium][color=blue][b]1. 网络服务器方式[/b][/color][/size]

网络服务器方式对应的Driver是org.apache.derby.jdbc.ClientDriver,它的#connect()方法如下所示:


	public java.sql.Connection connect(String url, java.util.Properties properties) throws java.sql.SQLException {
org.apache.derby.client.net.NetConnection conn;
try {
if (exceptionsOnLoadDriver__ != null) {
throw exceptionsOnLoadDriver__;
}

if (properties == null) {
properties = new java.util.Properties();
}

/* URL的格式类似于jdbc:derby://127.0.0.1:1527/database;create=true这种 */

/* URL格式分析 */
java.util.StringTokenizer urlTokenizer = new java.util.StringTokenizer(url, "/:= \t\n\r\f", true);

int protocol = tokenizeProtocol(url, urlTokenizer);
if (protocol == 0) {// 错误的URL前缀
return null;
}

String slashOrNull = null;
if (protocol == DERBY_REMOTE_PROTOCOL) {// 如果是网络方式的URL
try {
slashOrNull = urlTokenizer.nextToken(":/");
} catch (java.util.NoSuchElementException e) {
throw new SqlException(null, new ClientMessageId(SQLState.MALFORMED_URL), url, e);
}
}
/* 地址 */
String server = tokenizeServerName(urlTokenizer, url); // "/server"
/* 端口 */
int port = tokenizeOptionalPortNumber(urlTokenizer, url); // "[:port]/"
if (port == 0) {// port没有的话就设为默认的1527
port = ClientDataSource.propertyDefault_portNumber;
}

/* 数据库名 */
String database = tokenizeDatabase(urlTokenizer, url); // "database"
/* 这里还要加上一些URL中的参数进去,比如create=true这种 */
java.util.Properties augmentedProperties = tokenizeURLProperties(url, properties);
database = appendDatabaseAttributes(database, augmentedProperties);

int traceLevel;
try {
traceLevel = ClientDataSource.getTraceLevel(augmentedProperties);
} catch (java.lang.NumberFormatException e) {
throw new SqlException(null, new ClientMessageId(SQLState.TRACELEVEL_FORMAT_INVALID), e);
}

org.apache.derby.client.am.LogWriter dncLogWriter = ClientDataSource.computeDncLogWriterForNewConnection(
java.sql.DriverManager.getLogWriter(), ClientDataSource.getTraceDirectory(augmentedProperties),
ClientDataSource.getTraceFile(augmentedProperties), ClientDataSource
.getTraceFileAppend(augmentedProperties), traceLevel, "_driver", traceFileSuffixIndex_++);

/* 这步是获得连接的过程,下面要重点看一下 */
conn = (org.apache.derby.client.net.NetConnection) getFactory().newNetConnection(
(org.apache.derby.client.net.NetLogWriter) dncLogWriter, java.sql.DriverManager.getLoginTimeout(),
server, port, database, augmentedProperties);
} catch (SqlException se) {
throw se.getSQLException();
}

if (conn.isConnectionNull())
return null;

return conn;
}



这里的#getFactory()方法就是首先要关注的地方之一,

	public static ClientJDBCObjectFactory getFactory() {
if (factoryObject != null)
return factoryObject;
if (Configuration.supportsJDBC40()) {// 由于我的JDK是1.6的,只关注JDBC4.0的部分
factoryObject = createJDBC40FactoryImpl();
} else {
factoryObject = createDefaultFactoryImpl();
}
return factoryObject;
}

private static ClientJDBCObjectFactory createJDBC40FactoryImpl() {
final String factoryName = "org.apache.derby.client.net.ClientJDBCObjectFactoryImpl40";
try {
return (ClientJDBCObjectFactory) Class.forName(factoryName).newInstance();
} catch (ClassNotFoundException cnfe) {
return createDefaultFactoryImpl();
} catch (InstantiationException ie) {
return createDefaultFactoryImpl();
} catch (IllegalAccessException iae) {
return createDefaultFactoryImpl();
}
}


通过这里获得了一个org.apache.derby.client.net.ClientJDBCObjectFactoryImpl40的实例,它就是用来最后获取Connection实例的,回到之前的#connect()方法,这里调用了ClientJDBCObjectFactory的#newNetConnection()去获得Connection实例,


	public org.apache.derby.client.am.Connection newNetConnection(org.apache.derby.client.am.LogWriter netLogWriter,
String user, String password, org.apache.derby.jdbc.ClientBaseDataSource dataSource, int rmId,
boolean isXAConn) throws SqlException {
return (org.apache.derby.client.am.Connection) (new NetConnection40((NetLogWriter) netLogWriter, user,
password, dataSource, rmId, isXAConn));
}



这里可以看出,其实是实例化了一个NetConnection40的实例返回给调用端,也就是说以后进一步的讨论都可以从NetConnection40开始了。


[size=medium][color=blue][b]2. 嵌入式方式[/b][/color][/size]

下面就要看看嵌入式方式了,JDBC4.0的嵌入式Driver是Driver40这个类,不过这个类并没有重写#connect()方法,可以沿着继承树向上,在它的父类InternalDriver中看到这个方法


	public Connection connect(String url, Properties info) throws SQLException {
if (!acceptsURL(url)) {
return null;
}

/* 如果内存过低,那么不要尝试获取连接,直接抛出异常 */
if (EmbedConnection.memoryState.isLowMemory()) {
throw EmbedConnection.NO_MEM;
}

/* 是否要提供一个默认链接,URL是"jdbc:default:connection" */
boolean current = url.equals(Attribute.SQLJ_NESTED);

if (current) {
ConnectionContext connContext = getConnectionContext();
if (connContext != null) {
return connContext.getNestedConnection(false);

}
return null;
}

FormatableProperties finfo = null;

try {
/* 获得URL中的属性,还包括了用户名和密码 */
finfo = getAttributes(url, info);
info = null; // ensure we don't use this reference directly again.

/* 如果参数中包括了"shutdown",那么是要通知服务器关闭的 */
boolean shutdown = Boolean.valueOf(finfo.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue();

if (shutdown) {// 关闭操作
if (InternalDriver.getDatabaseName(url, finfo).length() == 0) {
if (this.getAuthenticationService() == null)
throw Util.generateCsSQLException(SQLState.LOGIN_FAILED, MessageService
.getTextMessage(MessageId.AUTH_NO_SERVICE_FOR_SYSTEM));

if (!this.getAuthenticationService().authenticate((String) null, finfo)) {
throw Util.generateCsSQLException(SQLState.NET_CONNECT_AUTH_FAILED, MessageService
.getTextMessage(MessageId.AUTH_INVALID));
}

Monitor.getMonitor().shutdown();

throw Util.generateCsSQLException(SQLState.CLOUDSCAPE_SYSTEM_SHUTDOWN);
}
}

/* 获得嵌入式方式的连接 */
EmbedConnection conn = getNewEmbedConnection(url, finfo);

if (conn.isClosed()) {
return null;
}

return conn;
} catch (OutOfMemoryError noMemory) {// 这个好像不能捕捉到吧??
EmbedConnection.memoryState.setLowMemory();
throw EmbedConnection.NO_MEM;
} finally {
if (finfo != null)
finfo.clearDefaults();
}
}


这段代码还是很好理解的,后边的#getNewEmbedConnection()方法各个不同JDBC版本的Driver就不尽相同了,我们来看一下JDBC4.0的好了,就是在Driver4里定义的那个,

	protected EmbedConnection getNewEmbedConnection(String url, Properties info) throws SQLException {
return new EmbedConnection40(this, url, info);
}


非常简单,返回了一个EmbedConnection40作为Connection的实现。

至此,网络服务器方式和嵌入式方式的连接获取就都分析完了,对于JDBC4.0,分别是NetConnection40和EmbedConnection40类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值