jdbc 分析一

其实jdbc用了很长时间了,一直就是使用

Class.forName(classname);

Connection conn=DriverManager.getConnection();

也一直就很奇怪,为什么这样就可以进行数据库连接了。

 

 

问题1.为什么一句Class.forName(drivername)以后就可以使用DriverManager来获取Connection了?

很多书上的解释是:Class.forName()会向DriverManager注册jdbc驱动程序。但是Class.forName()只是用来根据类的全限定名来加载类,并返回该类的Class而已。这是怎么回事?

刚下载了一个mysql的驱动程序com.mysql.jdbc.Driver,就拿它来分析一下

com.mysql.jdbc.Driver是这样定义的:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {

 static {

  try {

   java.sql.DriverManager.registerDriver(new Driver());

  } catch (SQLException E) {

   throw new RuntimeException("Can't register driver!");

  }

 }

 public Driver() throws SQLException {

 }

}

很简单啊,它实现了java.sql.Driver这个接口,并且继承了NonRegisteringDriver,NonRegisteringDriver或者它的超类一定实现了java.sql.Driver中定义的方法,因为com.mysql.jdbc.Driver并没有实现而且也不是abstract。

关键在于static块,它会在类被加载的时候执行。他生成了一个Driver的实例并且向DriverManager注册。啊哈,明白了为什么仅仅一句Class.forName(drivername)就可以注册jdbc驱动程序了。

 

 

问题2.DriverManager是怎样保存注册的jdbc驱动程序的呢?

现在肯定要看java.sql.DriverManager这个类了。这是一个无法生成实例的类,也无法被继承,因为它的构造函数是私有的,为的就是防止生成一个实例。它的所有的方法都是static的。当然,它的所有属性也是static的 ,因为既然无法生成实例,所以实例属性也就没有任何必要。

该类定义了一个DriverInfo类型的向量drivers用来存放已经注册的驱动程序。

private static java.util.Vector drivers = new java.util.Vector();

DriverInfo类的定义,也很简单,只是简单的记录驱动程序的实例,以及Class,以及该驱动程序类的全限定名。

class DriverInfo {

    Driver         driver;

    Class          driverClass;

    String         driverClassName;

    public String toString() {

 return ("driver[className=" + driverClassName + "," + driver + "]");

    }

}

DriverManager.registerDriver是这样定义的:

    public static synchronized void registerDriver(java.sql.Driver driver)

 throws SQLException {

 if (!initialized) {

     initialize();

 }

      

 DriverInfo di = new DriverInfo();

 di.driver = driver;

 di.driverClass = driver.getClass();

 di.driverClassName = di.driverClass.getName();

 drivers.addElement(di);

 println("registerDriver: " + di);

    }

这个函数的内容也是一幕了然的。先不去管 if (!initialized) {initialize();},其余的部分,只是生成了一个DriverInfo,并且设定了DriverInfo的属性,再把它加入到drivers里面去。

再看看initialize(),原来它是用来处理使用jvm参数来指定驱动程序的情况。例如我可以通过java -Djdbc.drivers=com.mysql.jdbc.Driver来指定jdbc驱动程序。

那个println是一个类似日志的功能。可以通过设置logStream或者logWriter来改变日志的记录位置。

例如,我可以这样:

 DriverManager.setLogStream(System.out);

 Connection conn=DriverManager.getConnection("jdbc:mysql://localhost/test","user","pass");

 conn.close();

java -Djdbc.drivers=com.mysql.jdbc.Driver=com.mysql.jdbc.Driver MyClass

执行结果:

DriverManager.getConnection("jdbc:mysql://localhost/test")

DriverManager.initialize: jdbc.drivers = com.mysql.jdbc.Driver

DriverManager.Initialize: loading com.mysql.jdbc.Driver

registerDriver: driver[className=com.mysql.jdbc.Driver,com.mysql.jdbc.Driver@5224ee]

JDBC DriverManager initialized

    trying driver[className=com.mysql.jdbc.Driver,com.mysql.jdbc.Driver@5224ee]

getConnection returning driver[className=com.mysql.jdbc.Driver,com.mysql.jdbc.Driver@5224ee]

这样就可以看到jdbc驱动程序被加载的过程。

累了,先暂时看到这里吧,和我想的差不多,Driver果然是在加载类的时候用static块来执行某个函数来加载的。