JAVA JDBC(MySQL)驱动源码分析(三)



原文链接: https://blog.csdn.net/brilliancezhou/article/details/5433869


第二篇中讲解了如何装载驱动,以及它的初始化过程。
本篇分析一下连接数据库时使用的获取数据库连接的代码:

  1. DriverManager.getConnection(“jdbc:mysql://localhost:3306/test”,”root”,”123”);  
DriverManager.getConnection(“jdbc:mysql://localhost:3306/test”,”root”,”123”);

DriverManager.getConnection方法有三种重载方式,这里我们使用带有三个参数的方法,第一个表示数据库的URL, 第二、三个分别
是用户名和密码。获取数据库连接如此简单,只要把三个参数准确无误的写上去,连接肯定就能获取。但是连接方法中到底给我们做
了哪些工作呢? 下面找到DriverManager类的静态方法getConnection源码一探究竟。

  1. public static Connection getConnection(String url,   
  2.     String user, String password) throws SQLException {  
  3.         java.util.Properties info = new java.util.Properties(); ///1  
  4.         // Gets the classloader of the code that called this method, may   
  5.     // be null.  
  6.     ClassLoader callerCL = DriverManager.getCallerClassLoader(); ///2  
  7.     if (user != null) {  
  8.         info.put(”user”, user);  
  9.     }  
  10.     if (password != null) {  
  11.         info.put(”password”, password);  
  12.     }  
  13.         return (getConnection(url, info, callerCL)); ///3  
  14.     }  
public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); ///1 // Gets the classloader of the code that called this method, may // be null. ClassLoader callerCL = DriverManager.getCallerClassLoader(); ///2 if (user != null) { info.put(“user”, user); } if (password != null) { info.put(“password”, password); } return (getConnection(url, info, callerCL)); ///3 }

1处定义了一个Properties对象,java.util.Properties它是用来在文件中存储键值对的,其中键和值是用等号分隔的。可以将值以
key-value的形式存入Properties.
2处调用方法getCallerClassLoader得到类装载器对象, 这个地方有点意思,既然是调用方法,怎么变成了下面这种形式呢?根本就
不见方法体。
源码:

  1. private static native ClassLoader getCallerClassLoader();  
private static native ClassLoader getCallerClassLoader();

getCallerClassLoader()是一个静态原生方法,返回类型为ClassLoader, 被声明为native, 说明这个方法是一个原生方法,也就是说
这个方法是用C/C++语言实现的,并且被编译成了DLL,由JAVA调用。这些函数的实体在DLL中,JDK源码并不包含,在JAVA源文件中是
找不到源代码的。不同的平台其实现也有所差异。这也是JAVA的底层机制,实际上JAVA就是在不同的平台上调用不同的native方法实
现对操作系统的访问。native关键字一般是和C/C++联合开发的时候使用。如果标明为native 要求运行时通知操作系统,这个函数必
须给我实现,JAVA需要调用。如果未实现,那么调用时会抛出一个异常java.lang.UnsatisfiedLinkError
接下来判断用户名和密码,并将其存放到Properties对象中:

  1. if (user != null) {  
  2.         info.put(”user”, user);  
  3.     }  
  4.     if (password != null) {  
  5.         info.put(”password”, password);  
  6.     }  
if (user != null) { info.put(“user”, user); } if (password != null) { info.put(“password”, password); }

调用获取连接的另一个重载方法
getCollection(String url, java.util.Properties info, ClassLoader callerCL)

  1. return (getConnection(url, info, callerCL));  
return (getConnection(url, info, callerCL));

getConnection(url, info, callerCL) 源码:

  1.    private static Connection getConnection(  
  2. String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {  
  3. java.util.Vector drivers = null;  
  4. synchronized(DriverManager.class) {    
  5.   // synchronize loading of the correct classloader.  
  6.   if(callerCL == null) {  
  7.       callerCL = Thread.currentThread().getContextClassLoader();  
  8.    }      
  9. }   
  10.    
  11. if(url == null) {  
  12.     throw new SQLException(“The url cannot be null”“08001”);  
  13. }  
  14.      
  15. println(”DriverManager.getConnection(/”“ + url + ”/“)”);  
  16.      
  17. if (!initialized) {  
  18.     initialize();  
  19. }  
  20. synchronized (DriverManager.class){   
  21.            // use the readcopy of drivers  
  22.     drivers = readDrivers;    
  23.        }  
  24. // Walk through the loaded drivers attempting to make a connection.  
  25. // Remember the first exception that gets raised so we can reraise it.  
  26. SQLException reason = null;  
  27. for (int i = 0; i < drivers.size(); i++) {  
  28.     DriverInfo di = (DriverInfo)drivers.elementAt(i);  
  29.        
  30.     // If the caller does not have permission to load the driver then   
  31.     // skip it.  
  32.     if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {  
  33.     println(”    skipping: ” + di);  
  34.     continue;  
  35.     }  
  36.     try {  
  37.     println(”    trying ” + di);  
  38.     Connection result = di.driver.connect(url, info);  
  39.     if (result != null) {  
  40.         // Success!  
  41.         println(”getConnection returning ” + di);  
  42.         return (result);  
  43.     }  
  44.     } catch (SQLException ex) {  
  45.     if (reason == null) {  
  46.         reason = ex;  
  47.     }  
  48.     }  
  49. }  
  50.      
  51. // if we got here nobody could connect.  
  52. if (reason != null)    {  
  53.     println(”getConnection failed: ” + reason);  
  54.     throw reason;  
  55. }  
  56.      
  57. println(”getConnection: no suitable driver found for ”+ url);  
  58. throw new SQLException(“No suitable driver found for ”+ url, “08001”);  
  59.    }  
private static Connection getConnection( String url, java.util.Properties info, ClassLoader callerCL) throws SQLException { java.util.Vector drivers = 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 + “/”)”); if (!initialized) { initialize(); } synchronized (DriverManager.class){ // use the readcopy of drivers drivers = readDrivers; } // Walk through the loaded drivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLException reason = null; for (int i = 0; i < drivers.size(); i++) { DriverInfo di = (DriverInfo)drivers.elementAt(i); // If the caller does not have permission to load the driver then // skip it. if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) { println(” skipping: ” + di); continue; } try { println(” trying ” + di); Connection result = di.driver.connect(url, info); if (result != null) { // Success! println(“getConnection returning ” + di); return (result); } } catch (SQLException ex) { if (reason == null) { reason = ex; } } } // 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”); }

此方法代码较多,我们一步步来分析。
1、    传参
从前面的那个getConnection方法中形成的三个参数传递到这个getConnection方法中, 参数包括连接数据库的URL,包装了用户名和
密码的对象info, 通过调用原生函数返回的类装载器callerCL
2、    同步DriverManager.class
同步DriverManager的Class对象,synchronized同步的对象为DriverManager.class,是为同步正确的类加载器来加载类,在同步块
中判断传入的类装载器对象是否存在,如果为null, 通过当前线程来获取上下文类装载器,保证JDBC驱动程序类以外的rt.jar中的类
可以在这里被加载。有关于Thread和synchronized读者可以参考java多线程编程

  1. synchronized(DriverManager.class) {    
  2.       if(callerCL == null) {  
  3.           callerCL = Thread.currentThread().getContextClassLoader();  
  4.        }  
  5.     }   
synchronized(DriverManager.class) { if(callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } }

3、    判断URL,如果为null则抛出SQLException异常
判断initialized的值,如果未初始化,继续调用初始化方法,此处在第二篇中已详细解释初始化过程,初始化之后writeDrivers 和readDrivers 将会有系统所有驱动数据,接下来使用synchronized同步DriverManager.class对象, 将方法中定义的集合drivers 引用 readDrivers对象,readDrivers是从writeDrivers拷贝过来

  1. if(url == null) {  
  2.     throw new SQLException(“The url cannot be null”“08001”);  
  3. }  
  4. println(”DriverManager.getConnection(/”“ + url + ”/“)”);  
  5. if (!initialized) {  
  6. initialize();  
  7. }  
  8. synchronized (DriverManager.class) {   
  9.     // use the readcopy of drivers  
  10. drivers = readDrivers;    
  11.  }  
if(url == null) { throw new SQLException(“The url cannot be null”, “08001”); } println(“DriverManager.getConnection(/”” + url + “/”)”); if (!initialized) { initialize(); } synchronized (DriverManager.class) { // use the readcopy of drivers drivers = readDrivers; }

4、    遍历驱动
通过for循环,遍历drivers集合,其中每个元素的类型为DriverInfo, 这个在第二篇中也有详细描述
首先取得集合中的每一个对象元素,调用getCallerClass()方法

  1.     for (int i = 0; i < drivers.size(); i++) {  
  2.         DriverInfo di = (DriverInfo)drivers.elementAt(i);  
  3.         if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {  
  4.             println(”    skipping: ” + di);  
  5.             continue;  
  6.         }  
  7. ……  
  8. }  
for (int i = 0; i < drivers.size(); i++) { DriverInfo di = (DriverInfo)drivers.elementAt(i); if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) { println(” skipping: ” + di); continue; } …… }

getCallerClass方法源码:

  1. private static Class getCallerClass(ClassLoader callerClassLoader,   
  2.                     String driverClassName) {  
  3. Class callerC = null;  
  4. try {  
  5. callerC = Class.forName(driverClassName, true, callerClassLoader);  
  6. }  
  7. catch (Exception ex) {  
  8.         callerC = null;             
  9.     }  
  10.     return callerC;  
  11.     }  
private static Class getCallerClass(ClassLoader callerClassLoader, String driverClassName) { Class callerC = null; try { callerC = Class.forName(driverClassName, true, callerClassLoader); } catch (Exception ex) { callerC = null; } return callerC; }

    这个方法返回一个Class对象,通过指定的类装载器来装载驱动类。这个方法内做得非常小心,如果出现异常都会把需要返
回的Class对象置为null.
    在if语句中调用getCallerClass方法得到的Class 对象和每一个驱动的Class对象比较,不相等的话就继续执行下一次循环
,否则都调用Driver的connect方法,传入url, 和 info,通过这个方法返回Connection连接对象

  1. Connection result = di.driver.connect(url, info);  
Connection result = di.driver.connect(url, info);

 

Driver接口的实现类中的connect方法具体所做的工作将在下一篇中详述

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值