JDBC 编程步骤
1. 加载驱动程序:
Class.forName(driverClass) //加载MySql驱动 Class.forName("com.mysql.jdbc.Driver") //加载Oracle驱动 Class.forName("oracle.jdbc.driver.OracleDriver")
2. 获得数据库连接:
DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/imooc", "root", "root");
3. 创建Statement\PreparedStatement对象:
conn.createStatement(); conn.prepareStatement(sql);
对于第一个步骤,大家可能会有疑问,加载驱动好像在后面的代码中没有引用,这一步骤是不是没起到作用呢?
其实不是的,Class.forName(driverClass)这一步骤主要是 强制JVM将com.mysql.jdbc.Driver这个类加载入内存,并将其注册到DriverManager类,然后根据DriverManager.getConnection(url,user,pwd)中的url找到相应的驱动类,最后调用该该驱动类的connect(url, info)来获得connection对象。
以mysql驱动为例,来分析一下驱动程序的源代码
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
mysql的Driver驱动继承了NonRegisteringDriver,而Driver本身只有一个静态代码块,代码块中的内容是new一个Driver对象,注册到DriverManager中。而在一个类加载入内存的时候,类中的静态代码块会得到执行,所以通过Class.forName("com.mysql.jdbc.Driver")之后,内存中就会有一个Driver对象,并且该对象注册到了DriverManager中。
DriverManager.registerDriver源码:
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
DriverManager把Driver对象封装成了DriverInfo放在了registeredDrivers,而registeredDrivers就是一个list
通过图示可以更容易看出来之间的关系。
在JDBC驱动管理中,sun主要定义了1个接口Driver和两个类:DirverManager和DriverInfo。每个JDBC驱动程序必须实现 Driver接口,
而DriverManager 则负责管理所有的Driver对象,包含注册Driver;选择合适的Driver来建立到某个数据库的连接;以及进行一些Driver的信息管理等。 DriverInfo非常简单,用于保存Driver的信息。
通过第一个步骤已经创建了mysql驱动对象,并将其注册到了DirverManager中,接下来我们看下第二步是如何获取连接的。
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
// Walk through the loaded registeredDrivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
可以和清晰的看到,该方法就是遍历了registeredDrivers,并调用注册的Driver的connect方法。
参考的文献:
https://www.cnblogs.com/liuxianan/archive/2012/08/04/2623258.html