日期:2014-05-16 浏览次数:20298 次
JDBC是作为连接数据库的渠道之一,封装了一些与数据库交互的接口。看了一些源码,现在就来探寻一下JDBC的原理。
JDK中给了几个接口比如说Connection,Statement,ResultSet。这些都是在用JDBC中比较常用的接口,这些接口定义了与数据库的交互规则。具体的实现都由具体的类库或者厂商实现。目前比较常用的数据库有Mysql,Oracle,Sql Server。这些具体的数据库所实现的通信协议都会有差异。而JDBC就需要屏蔽这些差异,对外提供一个统一而且简单的接口。对于使用者而言,他只要关心如何创立连接,而不需要关心里面的具体通信协议。如果看源码就会知道其内部都是用TCP/IP通信协议进行通信,如果自己要实现一个JDBC这样的API的话则需要了解具体的数据库的通信协议。但是这些都不是程序员需要关心的事情。他们更加关心偏业务的事情。比如我一条SQL语句简单的提交就可以实现对数据库的增删改查,如何用已有的接口实现事务的回滚。
好了,废话不多讲。先看看一个重量级的接口Connection。顾名思议,连接,和数据库交互最基本的就是要和数据库建立连接。这个对象并非我们简单的new出来,而是由一个叫做DriverManager的管理者给我们创建好的。先上传一张Connection创建的时序图,时序图中完整的描述出一个Connection的创建。
Connection conn = DriverManager.getConnection(url,user,password);上面一行代码就是一条非常常用的建立连接的方法。这里问题就出来了,我们拿到的是Connection接口,而具体的Connection实现类又由谁来创建呢?
static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }上面这段代码是com.mysql.jdbc.Driver里面一段静态注册的代码。这段代码的意图很明显,在DriverManager里面注册一个具体的Driver类(PS:里面的new Driver()正是com.mysql.jdbc.Driver)。
for (int i = 0; i < drivers.size(); i++) { DriverInfo di = (DriverInfo)drivers.elementAt(i); // If the caller does not have permission to load the driver then // skip it. if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) { println(" skipping: " + di); continue; } try { println(" trying " + di); Connection result = di.driver.connect(url, info); if (result != null) { // Success! println("getConnection returning " + di); return (result); } } catch (SQLException ex) { if (reason == null) { reason = ex; } } }
我们再看看NonRegisteringDriver(Driver正是继承于它)这个类的方法。其他的也不是现在需要关心的,里面Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance(host(props), port(props), props, database(props), url);正是核心所在,当然ConnectionImpl里面做了很多操作,比如说Socket之类的等等。有兴趣的可以看源码。
public java.sql.Connection connect(String url, Properties info) throws SQLException { if (url != null) { if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) { return connectLoadBalanced(url, info); } else if (StringUtils.startsWithIgnoreCase(url, REPLICATION_URL_PREFIX)) { return connectReplicationConnection(url, info); } } Properties props = null; if ((props = parseURL(url, info)) == null) { return null; } try { Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance( host(props), port(props), props, database(props), url);//这里终于可以看到具体的Connection实现类。 return newConn; } catch (SQLException sqlEx) { // Don't wrap SQLExceptions, throw // them un-changed. throw sqlEx; } catch (Exception ex) { SQLException sq