Java中,我们在加载数据驱动程序的时候常常用一下两种方法:
方法1:
System.setProperty("jdbc.drivers","com.microsoft.sqlserver.jdbc.SQLServerDriver: com.mysql.jdbc. Driver");
DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;DataBaseName=NorthWind","test","test");
方法2:
Class.forName("jdbc.drivers","com.microsoft.sqlserver.jdbc.SQLServerDriver");
DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;DataBaseName=NorthWind","test","test");
那么以上这两种方式有什么不同!他们的连接创建过程是怎样的?
在方法1中:我们首先把我们需要的jdbc驱动程序添加到了jdbc.drivers系统属性中(在这里我们可以同时添加多个驱动程序,用:号隔开即可),在调用DriverManager.getConnection
方法获取连接时系统实际是在DriverManager的loadInitialDrivers方法中加载我们第一行中注册的驱动程序,并向DriverManager注册的!loadInitialDrivers方法的主要代码如下:
private static void loadInitialDrivers() {
String drivers;
try
{
//获取系统属性jdbc.drivers的值!
drivers = (String) java.security.AccessController.doPrivileged(new sun.security.action.GetPropertyAction("jdbc.drivers"));
}
catch (Exception ex)
{
drivers = null;
}
DriverService ds = new DriverService();
java.security.AccessController.doPrivileged(ds);
if (drivers == null)
{
return;
}
while (drivers.length() != 0)
{
//解析系统属性jdbc.drivers的值。
int x = drivers.indexOf(':');
String driver;
if (x < 0)
{
driver = drivers;
drivers = "";
}
else
{
driver = drivers.substring(0, x);
drivers = drivers.substring(x+1);
}
if (driver.length() == 0)
{
continue;
}
try
{
//加载并初始华系统属性中配置的驱动程序!
Class.forName(driver, true,ClassLoader.getSystemClassLoader());
}
catch (Exception ex)
{
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
从上面的代码可以看出jdbc驱动程序的加载主要是在上面的绿色代码部分进行的,那么Class.forName方法加载的驱动程序是如何和DriverManager类关联起来的呢?原来JDBC规范中明确要求JDBC的驱动实现必须向DriverManager注册自己,即任何一个JDBC Driver的驱动Driver类的代码都必须类似如下:
public class MyJDBCDriver implements Driver { static { DriverManager.registerDriver(new MyJDBCDriver()); }
} |
|
在driverManager类中调用Class.forName方法,加载完相应的驱动类,在执行静态代码时,会在静态代码中实例化一个jdbc驱动并把它向DriverManager注册!并最终吧这个实例保存在DriverManager的静态域readDrivers数组中,代码如下:
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();
//把信息实例保存在Vecotor类型的静态变量writeDrivers和readDrivers中
writeDrivers.addElement(di);
readDrivers = (java.util.Vector) writeDrivers.clone();
}
现在我们完成了驱动程序的加载!然后DriverManager会根据传入的url参数信息调用driver.connect(url, info)方法并返回连接成功的连接实例,代码如下:
for (int i = 0; i < drivers.size(); i++)
{
//循环取出已经注册的驱动程序
DriverInfo di = (DriverInfo)drivers.elementAt(i);
if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass )
{
continue;
}
try
{
//尝试用取出的驱动程序进行连接
Connection result = di.driver.connect(url, info);
//连接成功返回此链接
if (result != null)
{
return (result);
}
}
catch (SQLException ex)
{
//连接过程抛出异常!
if (reason == null)
{
reason = ex;
}
}
}
//抛出异常
if (reason != null)
{
throw reason;
}
//没有相匹配的驱动程序
throw new SQLException("No suitable driver found for "+ url, "08001");
方法2和方法1的第一行代码是不一样的,那么它又是通过一个什么养的过程获取连接的呢!
方法2中直接调用Class.forName方法加载相应的数据库驱动!并在加载驱动后执行相应驱动程序的静态代码,实例化驱动,并把驱动实例向driverManager进行注册!,然后DriverManager在循环每一个驱动找出连接成果的连接实例并返回。
从中可以看出这两种获取连接的方法本质上是一样的,都是通过Class.forName方法加载并注册驱动实例,然后在DriverManager的getConnection时调用dirver.connect方法获取连接实例!它们的不同之处在于,方法1是被动的,它把驱动程序的加载交给了DriverManager去做,而方法2是主动地加载相应驱动,并向driverManager进行注册!