@pastqing
2015-05-28T19:45:23.000000Z
字数 2810
阅读 2277
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 DriverManager
throw 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 {
//加载mysql
Class.forName("com.mysql.jdbc.Driver");
//加载sqlserver
Class.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是怎样实现载入驱动的。