mysql驱动加载原理_老调重弹:JDBC系列 之 lt;驱动载入原理全面解析gt;
前言
近期在研究Mybatis框架,因为该框架基于JDBC。想要非常好地理解和学习Mybatis,必需要对JDBC有较深入的了解。所以便把JDBC 这个东东翻出来。好好总结一番,作为自己的笔记,也是给读者一个參考~~~下面是本文的组织结构。读者能够点击上面的文件夹查看:
概述
普通情况下。在应用程序中进行数据库连接,调用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是否有效) 。拓展阅读:经常使用数据库
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进行创建连接就会显得代码杂乱无章。而且还easy出错。而且不方便管理。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系列 之
mysql驱动加载原理_老调重弹:JDBC系列 之 lt;驱动载入原理全面解析gt;相关推荐
- mysql 预加载缓存_预加载与缓存
最近的项目中为了能够提升那么一丢丢性能,尝试了一下对 chunks 进行预加载处理.虽然做了异步加载的处理,但是项目大小决定了还是有多个异步的 chunk.js 需要进行预加载,这里我指的是 prel ...
- springboot配置文件加载顺序_「SpringBoot系列」配置文件加载优先级解析
SpringBoot提供了外部分配置功能,可以使用属性文件(properties).YAML(yml)文件.环境变量和命令行参数来进行处部参数配置,并t以特定的顺序来处理配置,以便于允许合理的覆盖值. ...
- 白加黑加载方式_“白加黑减”即曝光补偿的应用方法及原理全面详解——致新手新新手...
"白加黑减"即曝光补偿的应用方法及原理全面详解 --致新手新新手 本文对曝光补偿这一摄影基本技术及原理做一全面详细的分析和解释,旨在让受此困惑的新手能够从原理上彻底理解" ...
- mysql怎么加载数据库_如何导入mysql数据库
展开全部 方法一: 1.首先我e68a84e8a2ad3231313335323631343130323136353331333363393134们使用MySQL提供的命令行界面来导入数据库,确保自己 ...
- JDBC中驱动加载的过程分析
JDBC中驱动加载的过程分析 作者:kenty 来源:博客园 发布时间:2007-08-20 15:01 阅读:1100 次 原文链接 [收藏] 本篇从java.sql.Driver ...
- matlab 读取voi文件,VOI虚拟化下的Windows网卡驱动加载方法与流程
本发明涉及计算机技术领域,特别涉及VOI虚拟化下的Windows网卡驱动加载方法. 背景技术: 在VOI虚拟化方案中,首先需要确保网卡驱动能够提前加载到系统中,才能够实现通过网络来引导操作系统启动.现 ...
- 老调重弹:JDBC系列之驱动加载原理全面解析)
前言 最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解.所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读 ...
- 老调重弹:JDBC系列 之 驱动加载原理全面解析
前言 最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解.所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读 ...
- mysql驱动如何编写_解读MySQL驱动加载逻辑
解读MySQL驱动加载逻辑 我们很早之前就知道最基础的JDBC编写,先执行Class.forName方法,加载MySQL驱动.但是为什么加载过驱动后,后续的接口层的调用就会自动切换到MySQL的相关代 ...
- JDBC驱动加载机制详解以及spi机制
首先有两个问题: 1.java连接数据库时是否真的需要加载驱动? 2.JDBC如何区分多个驱动? 以下摘自:https://blog.csdn.net/buqutianya/article/detai ...
最新文章
- mysql 新建子查询_Mysql创建SQL子查询ALIAS
- ubuntu通过pem连接服务器
- 相机内参_鱼眼相机标定模型
- nodejs html引用js_NodeJS与模块系统
- mysql union后面查不出_mysql – 多个UNION查询不起作用
- 大牛用SSM框架实现了支付宝的支付功能,满满干货指导
- 怎么去除表中的系统导出的字符_EXCEL非常有用的字符函数LEN、LENB,财务工作者的必备利器...
- JUnit单元测试的几个规律总结
- linux实现普通用户只允许使用部分命令
- fir.im Weekly - 从零开始创建 Android 新项目
- 2022-01-11每日刷题打卡
- 测试日照强度的软件,日照分析软件FastSUN - 飞时达软件
- 大话数据结构 - 串
- word添加自定义样式(导入normal.dotm)
- Linux的远程传输文件scp及出现Permission denied (publickey).lost connection问题解决方法
- 基于python及图像识别的围棋棋盘棋子识别3——耗时优化(一行代码速度提高600倍)
- windows--XP的140个技巧!
- 密信(MeSince) — 免费的全自动邮件加密软件
- https请求,报错Could not establish trust relationship for the SSL/TLS secure channel
- MFC 显示对话框内鼠标单击点的坐标值
热门文章
- Spark优化一则 - 减少Shuffle
- 关于mongodb的可视化工具:nosql manager for mongodb
- mysql slave修改_MySql主从复制(初学笔记)
- Java中的标识符及其命名规则
- 中科大410分计算机排名第几,2021考研成绩发布:中科大400分无缘复试,中山大学321分登顶第二...
- 通过命令行获取计算机参数,Win32命令行参数的传到和获取
- mysql并行加载机制_Mysql表引擎优化
- linux tomcat启动nohup,linux下tomcat添加服务
- 【论文阅读】Deep Neural Networks for Learning Graph Representations | day14,15
- ckfinder java 源码,关于不再找java使用CKFinder的原因