最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

老调重弹:JDBC系列之<驱动加载原理全面解析)

来源:动视网 责编:小采 时间:2020-11-09 15:04:19
文档

老调重弹:JDBC系列之<驱动加载原理全面解析)

老调重弹:JDBC系列之<驱动加载原理全面解析):前言 最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解。所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读者一个参考~~~ 概述 一般情况下,在应用程序中进行数据库连接,调用J
推荐度:
导读老调重弹:JDBC系列之<驱动加载原理全面解析):前言 最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解。所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读者一个参考~~~ 概述 一般情况下,在应用程序中进行数据库连接,调用J


Driver的功能

java.sql.Driver接口规定了Driver应该具有以下功能:

其中:

acceptsURL(String url) 方法用来测试对指定的url,该驱动能否打开这个url连接。driver对自己能够连接的url会制定自己的协议,只有符合自己的协议形式的url才认为自己能够打开这个url,如果能够打开,返回true,反之,返回false;

例如:oracle定义的自己的url协议如下:

jdbc:oracle:thin:@//:/ServiceName

jdbc:oracle:thin:@::

oracle自己的acceptsURL(String url)方法如下:

	public boolean acceptsURL(String paramString) {
	if (paramString.startsWith("jdbc:oracle:")) {
	return (oracleDriverExtensionTypeFromURL(paramString) > -2);
	}

	return false;
	}

	private int oracleDriverExtensionTypeFromURL(String paramString) {
	int i = paramString.indexOf(58) + 1;

	if (i == 0) {
	return -2;
	}
	int j = paramString.indexOf(58, i);

	if (j == -1) {
	return -2;
	}
	if (!(paramString.regionMatches(true, i, "oracle", 0, j - i))) {
	return -2;
	}
	++j;

	int k = paramString.indexOf(58, j);

	if (k == -1) {
	return -3;
	}
	String str = paramString.substring(j, k);

	if (str.equals("thin")) {
	return 0;
	}
	if ((str.equals("oci8")) || (str.equals("oci"))) {
	return 2;
	}

	return -3;
	}

由上可知oracle定义了自己应该接收什么类型的URL,自己能打开什么类型的URL连接(注意:这里acceptsURL(url)只会校验url是否符合协议,不会尝试连接判断url是否有效) 。拓展阅读:常用数据库 JDBC URL格式

connect(String url,Properties info)方法,创建Connection对象,用来和数据库的数据操作和交互,而Connection则是真正数据库操作的开始(在此方法中,没有规定是否要进行acceptsURL()进行校验)。

手动加载驱动 Driver 并实例化进行数据库操作的例子

	public static void driverTest(){
	try {
	//1.加载oracle驱动类,并实例化
	Driver driver = (Driver) Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();

	//2.判定指定的URL oracle驱动能否接受(符合oracle协议规则)
	boolean flag = driver.acceptsURL("jdbc:oracle:thin:@127.0.0.1:1521:xe");
	//标准协议测试
	boolean standardFlag1 = driver.acceptsURL("jdbc:oracle:thin:@//:/ServiceName");
	boolean standardFlag2 = driver.acceptsURL("jdbc:oracle:thin:@::");
	System.out.println("协议测试:"+flag+"\t"+standardFlag1+"\t"+standardFlag2);
	
	//3.创建真实的数据库连接:
	String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
	Properties props = new Properties();
	props.put("user", "louluan");
	props.put("password", "123456");
	Connection connection = driver.connect(url, props);
	//connection 对象用于数据库交互,代码省略。。。
	
	} catch (Exception e) {
	System.out.println("加载Oracle类失败!");
	e.printStackTrace();
	} finally{
	
	}
	}

上述的手动加载Driver并且获取连接的过程稍显笨拙:如果现在我们加载进来了多个驱动Driver,那么手动创建Driver实例,并根据URL进行创建连接就会显得代码杂乱无章,并且还容易出错,并且不方便管理。JDBC中提供了一个DriverManager角色,用来管理这些驱动Driver。

DriverManager角色

事实上,一般我们操作Driver,获取Connection对象都是交给DriverManager统一管理的。DriverManger可以注册和删除加载的驱动程序,可以根据给定的url获取符合url协议的驱动Driver或者是建立Conenction连接,进行数据库交互。

以下是DriverManager的关键方法摘要:

DriverManager 内部持有这些注册进来的驱动 Driver,由于这些驱动都是 java.sql.Driver 类型,那么怎样才能获得指定厂商的驱动Driver呢?答案就在于:

java.sql.Driver接口规定了厂商实现该接口,并且定义自己的URL协议。厂商们实现的Driver接口通过acceptsURL(String url)来判断此url是否符合自己的协议,如果符合自己的协议,则可以使用本驱动进行数据库连接操作,查询驱动程序是否认为它可以打开到给定 URL 的连接。

使用DriverManager获取指定Driver

对于驱动加载后,如何获取指定的驱动程序呢?这里,DriverManager的静态方法getDriver(String url)可以通过传递给的URL,返回可以打开此URL连接的Driver。
比如,我想获取oracle的数据库驱动,只需要传递形如jdbc:oracle:thin:@::或者jdbc:oracle:thin:@//:/ServiceName的参数给DriverManager.getDriver(String url)即可:

Driver oracleDriver =DriverManager.getDriver("jdbc:oracle:thin:@::");

实际上,DriverManager.getDriver(String url)方法是根据传递过来的URL,遍历它维护的驱动Driver,依次调用驱动的Driver的acceptsURL(url),如果返回acceptsURL(url)返回true,则返回对应的Driver:

	public static Driver getDriver(String paramString) throws SQLException {
	
	//省略部分代码。。
	Iterator localIterator = registeredDrivers.iterator();
	//遍历注册的驱动
	while (localIterator.hasNext()) {
	DriverInfo localDriverInfo = (DriverInfo) localIterator.next();
	if (isDriverAllowed(localDriverInfo.driver, localClass))
	try {
	//如果accepsURL() 为true,返回对应的driver
	if (localDriverInfo.driver.acceptsURL(paramString)) {
	//返回对应的driver
	return localDriverInfo.driver;
	}
	} catch (SQLException localSQLException) {
	}
	else
	println(" skipping: "+ localDriverInfo.driver.getClass().getName());
	}
	throw new SQLException("No suitable driver", "08001");
	//-----省略部分代码
	}

使用DriverManager注册和取消注册驱动Driver

在本博文开始的 驱动加载的过程 一节中,讨论了当使用Class.forName("driverName")加载驱动的时候,会向DriverManager中注册一个Driver实例。以下代码将验证此说法:

	public static void defaultDriver(){
	try {
	
	String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
	
	//1.将Driver加载到内存中,然后执行其static静态代码,创建一个OracleDriver实例注册到DriverManager中
	Class.forName("oracle.jdbc.driver.OracleDriver");
	//取出对应的oracle 驱动Driver
	Driver driver = DriverManager.getDriver(url);
	System.out.println("加载类后,获取Driver对象:"+driver);
	
	//将driver从DriverManager中注销掉
	DriverManager.deregisterDriver(driver);
	//重新通过url从DriverManager中取Driver
	driver = DriverManager.getDriver(url);
	System.out.println(driver);
	
	} catch (Exception e) {
	System.out.println("加载Oracle类失败!");
	e.printStackTrace();
	} finally{
	
	}
	}
以上代码主要分以下几步:

1. 首先是将 oracle.jdbc.driver.OracleDriver加载到内存中;

2. 然后便调用DriverManager.getDriver()去取Driver实例;

3. 将driver实例从DriverManager中注销掉;

4.尝试再取 对应url的Driver实例;

上述代码执行的结果如下:

从执行结果看,正好能够验证以上论述:当第四步再次获取对应url的 Driver 实例时,由于已经被注销掉了,找不到适当的驱动Driver,抛出了 "Not suitable driver" 的异常。

将上述的例子稍作变化,在注销掉了静态块创建的driver后,往DriverManager注册一个自己创建的Driver对象实例(具体步骤请看注释):

	public static void defaultDriver(){
	try {
	
	String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
	
	//1.将Driver加载到内存中,然后执行其static静态代码,创建一个OracleDriver实例注册到DriverManager中
	Driver dd = (Driver)Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
	//2.取出对应的oracle 驱动Driver
	Driver driver = DriverManager.getDriver(url);
	System.out.println("加载类后,获取Driver对象:"+driver);
	
	//3. 将driver从DriverManager中注销掉
	DriverManager.deregisterDriver(driver);
	
	//4.此时DriverManager中已经没有了驱动Driver实例,将创建的dd注册到DriverManager中
	DriverManager.registerDriver(dd);
	
	//5.重新通过url从DriverManager中取Driver
	driver = DriverManager.getDriver(url);
 
 System.out.println("注销掉静态创建的Driver后,重新注册的Driver: "+driver);
	System.out.println("driver和dd是否是同一对象:" +(driver==dd));
	} catch (Exception e) {
	System.out.println("加载Oracle类失败!");
	e.printStackTrace();
	} finally{
	
	}
	}
以下代码运行的结果:

以上代码先创建了一个Driver对象,在注销了DriverManager中由加载驱动过程中静态创建驱动之后,注册到系统中,现在DriverManager中对应url返回的Driver 即是在代码中创建的Driver对象。

使用DriverManager创建 Connection 连接对象

创建 Connection 连接对象,可以使用驱动Driver的 connect(url,props),也可以使用 DriverManager 提供的getConnection()方法,此方法通过url自动匹配对应的驱动Driver实例,然后调用对应的connect方法返回Connection对象实例。

Driver driver = DriverManager.getDriver(url);
	Connection connection = driver.connect(url, props);
上述代码等价于:
	Class.forName("oracle.jdbc.driver.OracleDriver");
	Connection connection = DriverManager.getConnection(url, props);

jdbc.drivers

DriverManager 作为 Driver 的管理器,它在第一次被使用的过程中(即在代码中第一次用到的时候),它会被加载到内存中,然后执行其定义的static静态代码段,在静态代码段中,有一个 loadInitialDrivers() 静态方法,用于加载配置在jdbc.drivers 系统属性内的驱动Driver,配置在jdbc.drivers 中的驱动driver将会首先被加载:

	static {
	loadInitialDrivers();//加载配置在jdbc.drivers系统变量中的驱动driver
	println("JDBC DriverManager initialized");
	SET_LOG_PERMISSION = new SQLPermission("setLog");
	}
	private static void loadInitialDrivers() {
	String str1;
	try {
	str1 = (String) AccessController
	.doPrivileged(new PrivilegedAction() {
	public String run() {
	return System.getProperty("jdbc.drivers");//返回jdbc.drivers值
	}
	});
	} catch (Exception localException1) {
	str1 = null;
	}

 //省略部分代码......
	if ((str1 == null) || (str1.equals("")))
	return;
	String[] arrayOfString1 = str1.split(":");
	println("number of Drivers:" + arrayOfString1.length);
	for (String str2 : arrayOfString1)
	try {
	//Class.forName加载对应的driver
	Class.forName(str2, true, ClassLoader.getSystemClassLoader());
	} catch (Exception localException2) {
	println("DriverManager.Initialize: load failed: "
	+ localException2);
	}
	}

以下是通过jdbc.drivers加载驱动driver的方式:

	String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
	//设置值系统变量jdbc.drivers
	System.setProperty("jdbc.drivers", "oracle.jdbc.driver.OracleDriver");
	//2.通过特定的url获取driver
	Driver driver = DriverManager.getDriver(url);
	//打印是否存在
	System.out.println(driver);
请记住:一定要在第一次使用DriverManager之前设置jdbc.drivers,因为DriverManager中的static静态代码段只会被执行一次!

-------------------------------------------------------------------------------------------------------------------------------------------------------------

以上是本文 老调重弹:JDBC系列 之 <驱动加载原理全面解析> 的全部内容,以上是自己心得,并非权威,如有不妥或者此错误之处,欢迎读者批评和斧正! 欢迎关注我的下一篇博文: 老调重弹:JDBC系列 之

文档

老调重弹:JDBC系列之&lt;驱动加载原理全面解析)

老调重弹:JDBC系列之<驱动加载原理全面解析):前言 最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解。所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读者一个参考~~~ 概述 一般情况下,在应用程序中进行数据库连接,调用J
推荐度:
标签: 加载 原理 驱动
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top