@pastqing
2015-05-28T11:45:23.000000Z
字数 2810
阅读 2489
java
在连接数据库的时候,需要加载相关数据库的驱动,加载驱动的方式有若干种,本文分析几种常见加载方式的具体过程。
以mysql为例, 加载驱动的时候我们经常会这样写:
Class.forName(driverName);Connection conn = DriverManager.getConnection();
先来分析一下Class.forName(String className)会发生什么。
阅读一下源码:
public static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);}
调用Class.forName(String className)时会调用forName0, 这个方法里面多了很多参数, 他们分别代表什么意思呢:
private static native Class<?> forName0(String name,boolean initialize,ClassLoader loader,Class<?> caller)throws ClassNotFoundException;
我们关注一下第二个参数initialize, 它的意思是否初始化该类。也就是说在调用Class.forName("com.mysql.jdbc.Driver")会发生驱动类的初始化。我们再看看mysql驱动类(driver):
static {try {java.sql.DriverManager.registerDriver(new Driver());} catch (SQLException E) {throw new RuntimeException("Can't register driver!");}}
在Driver类中,发现了一段静态块,初始化这个类的时候会调用这个静态块,那么DriverManager.registerDriver(new Driver())会发生呢?
public static synchronized void registerDriver(java.sql.Driver driver)throws SQLException {/* Register the driver if it has not already been added to our list */if(driver != null) {registeredDrivers.addIfAbsent(new DriverInfo(driver));} else {// This is for compatibility with the original DriverManagerthrow new NullPointerException();}println("registerDriver: " + driver);}
registerDriver方法会生成一个DriverInfo对象, 并将它添加到一个CopyOnWriteArrayList类型的list中去。CopyOnWriteArrayList是一种适用于高并发中读操作多的集合类型。
以上的所有操作就完成了一个驱动的注册,为后面我们DriverManager.getConnection()打下基础
下面我们看看DriverManager.getConnection()是如何实现的,这里我们截取一段代码:
for(DriverInfo aDriver : registeredDrivers) {if(isDriverAllowed(aDriver.driver, callerCL)) {try {println(" trying " + aDriver.driver.getClass().getName());Connection con = aDriver.driver.connect(url, info);if (con != null) {println("getConnection returning " + aDriver.driver.getClass().getName());return (con);}} catch (SQLException ex) {if (reason == null) {reason = ex;}}} else {println(" skipping: " + aDriver.getClass().getName());}}
我们可以看到,getConnection()其实就是遍历之前的CopyOnWriteArrayList列表,找到所有注册过的驱动,并打开连接。下面我们做个测试:
public class DemoDriver {public static void main(String[] args) {final String dbName = "root";final String dbPass = "123";final String dbURL = "jdbc:mysql://192.168.109.29:3306/educationcloudpayment";try {//加载mysqlClass.forName("com.mysql.jdbc.Driver");//加载sqlserverClass.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");//将日志信息重定向到标准输出DriverManager.setLogWriter(new java.io.PrintWriter(System.out));//DriverManager.getConnection(dbURL, dbName, dbPass);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}}
这里我们分别加载了mysql和sqlserver两个驱动,从日志输出可以看出其遍历过程。
下面我们在看看Apache Commons DbUtils是怎样实现载入驱动的。
