概述

一般情况下,在应用程序中进行数据库连接,调用JDBC接口,首先要将特定厂商的JDBC驱动实现加载到系统内存中,然后供系统使用。基本结构图如下:

驱动加载入内存的过程

这里所谓的驱动,其实就是实现了java.sql.Driver接口的类。如oracle的驱动类是 oracle.jdbc.driver.OracleDriver.class(此类可以在oracle提供的JDBC jar包中找到),此类实现了java.sql.Driver接口。

由于驱动本质上还是一个class,将驱动加载到内存和加载普通的class原理是一样的:使用Class.forName("driverName")。以下是将常用的数据库驱动加载到内存中的代码:

//加载Oracle数据库驱动

Class.forName("oracle.jdbc.driver.OracleDriver");

//加载SQL Server数据库驱动

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

//加载MySQL 数据库驱动

Class.forName("com.mysql.jdbc.Driver");

注意:Class.forName()将对应的驱动类加载到内存中,然后执行内存中的static静态代码段,代码段中,会创建一个驱动Driver的实例,放入DriverManager中,供DriverManager使用。

例如,在使用Class.forName() 加载oracle的驱动oracle.jdbc.driver.OracleDriver时,会执行OracleDriver中的静态代码段,创建一个OracleDriver实例,然后调用DriverManager.registerDriver()注册:

static {

Timestamp localTimestamp = Timestamp.valueOf("2000-01-01 00:00:00.0");

try {

if (defaultDriver == null) {

//创建一个OracleDriver实例,然后注册到DriverManager中

defaultDriver = new OracleDriver();

DriverManager.registerDriver(defaultDriver);

}

} catch (RuntimeException localRuntimeException) {

} catch (SQLException localSQLException) {

}

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是否有效) 。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是否符合自己的协议(这段话是作者所说,实际不一定是通过acceptURL方法判断,但逻辑顺序是对的,即先判断是否符合协议格式,再试图创建Connection实例),如果符合自己的协议,则可以使用本驱动进行数据库连接操作,查询驱动程序是否认为它可以打开到给定 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);

}

}

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静态代码段只会被执行一次!

加载mysql的jdbc驱动_JDBC驱动加载相关推荐

  1. com.mysql.cj.jdbc.Driver这个驱动类

    Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.D ...

  2. spring boot 2.0采用com.mysql.cj.jdbc.Driver数据库驱动引发的系统时间不一致问题

    首先简单描述一下项目情况,老板新注册了一家公司,既然有公司了肯定得有个公司门户网站.现在已经是web 2.0时代了,网站内容不可能再像以前那样全部采用静态html页面.于是开发了一个内容管理系统,简称 ...

  3. MySQL、JDBC、HTML、CSS、JavaScript、jQuery、tomcat、Http、Servlet、JSP、EL、JSTL、Maven、Cookie、Session(框架第一部分)

    第一章 MySQL 一 .数据库 1.什么是数据库? 所谓的数据库就是指存储和管理数据的仓库 2.数据库有哪些分类? 3.什么是关系型数据库? 底层以二维表的形式保存数据的库就是关系型数据库 stu- ...

  4. com.mysql.cj.jdbc.Driver连接失败解决办法

    com.mysql.cj.jdbc.Driver连接失败解决办法 com.mysql.cj.jdbc.Driver连接失败解决办法 (1)错误伊始 (2)怎么还是报错? (3)最终解决 com.mys ...

  5. mysql驱动为什么自动加载_为什么JDBC中加载驱动要使用反射?

    原文链接:https://www.cnblogs.com/homejim/p/8076481.html 在JDBC详解系列(一)之流程中,我将数据库的连接分解成了六个步骤. JDBC流程: 第一步:加 ...

  6. 数据库加载驱动问题(java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver)

    java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver 遇到此问题,首先检查IDEA外部库中是否有mysql数据库驱动.如下所示: 如果发 ...

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

    前言 最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解.所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读 ...

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

    前言 最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解.所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读 ...

  9. 正确加载MySQL驱动的语句_正确加载MySQL驱动的语句_____________________;_学小易找答案...

    [多选题]电子图书的特点是 [简答题] [单选题]为了准备病理学考试,王同学想在图书馆借一本人民卫生出版社出版的熊小亮编写的<病理学试题库>,经过检索发现该书都被借出去了 , 最方便快捷的 ...

  10. jdbc驱动_JDBC概述和CRUD

    第八章 JDBC的简介 8.1 简介 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问 ...

最新文章

  1. 美国空军把将人工智能纳入杀伤链列为最高优先事项之一
  2. Angular19 自定义表单控件
  3. 从一个实例,一窥docker进程管理
  4. MySQL删除关联表的数据
  5. CozyRSS开发记录19-窗口标题栏交互
  6. Rxjava、Retrofit返回json数据解析异常处理
  7. 3.关于QT中的MainWindow窗口,MenuBar,ToolBar,QuickTip等方面的知识点
  8. redis-Windows下安装与操作
  9. mysql分组获取其他字段_sqlserver group by后获取其他字段(多种方法)
  10. (116)FPGA面试题-FIFO相关参数与信号,为什么要用格雷码
  11. 通向财务自由之路08_入市或市场时机选择
  12. CCF201909-3 字符画(100分)【文本处理】
  13. PhpStorm-2017.3 注册激活
  14. ubuntu18.10 编译安装caffe gpu版本
  15. 最新linux 编程视频教程下载
  16. linux cximage动态库,64位Linux编译cximage手记
  17. 超级玛丽java_超级玛丽java实现源码
  18. DLP迈向NG DLP的进化之路
  19. android微博图片上传,安卓开发 新浪微博share接口实现发带本地图片的微博
  20. c语言中sub是什么指令,汇编 – SUB指令的目的是什么?

热门文章

  1. 电容式压力传感器分类与原理
  2. switch:欢迎进入迷你游戏平台,选择你喜爱的游戏
  3. mysql如何找回误删除数据_mysql如何找回误删除数据
  4. dhuacm出题网站搭建
  5. Pyspark 案例实践 假新闻分类
  6. 源码分享:打造「螃蟹火星车」,遥控、拍照、测距,还能做人脸检测;
  7. 知识图谱研究最新综述论文: 表示学习、知识获取与应用
  8. 前端学习之百叶窗效果
  9. vue中views新建文件夹的代码规范
  10. 如何写网站建设策划书