`
zhaonjtu
  • 浏览: 131137 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

JDBC中驱动加载的过程分析(转)

阅读更多

本篇从java.sql.Driver接口、java.sql.DriveManager类以及其它开源数据库的驱动类讨论JDBC中驱动加载的全过程以及JDBCFramework如何做到“可插拔”的细节。

       本篇包含了很多部分的内容。如类加载器、本地方法、对象锁、类锁、按功能或者状态分离锁、安全机制,对这些内容没有深入讨论!详情可以继续关注本博客!我在上篇主要关注驱动管理器的初始化、连接的建立、驱动的注册、驱动的遍列、驱动的取消注册以及DriverManager中的日志操作。

一、Driver接口

//Driver.java

package java.sql;

public interface Driver {

    Connection connect(String url, java.util.Properties info) throws SQLException;

    boolean acceptsURL(String url) throws SQLException;

    DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info) throws SQLException;

    int getMajorVersion();                                             //返回驱动的主版本号

    int getMinorVersion();                                             //返回驱动的次版本号

    boolean jdbcCompliant();                              //是否兼容于JDBC标准

}

       以上就是JDBC中的Driver接口,它是任何数据库提供商的驱动类必须实现的接口,驱动类必须实现该接口中的所有方法!简单吧!

       它之所以是一个接口,就是OO中经常谈到的“依赖倒转原则(DIPDependence Inverse Principle)”的具体应用了!在DriverManager类中可以看到:它使用的驱动都是Driver接口,从而依赖与高层,不依赖于实现。这样可以使用JDBC Framework管理和维护不同JDBC提供商的数据库驱动。

       JDBC Framework中允许加载多个数据库的驱动!相应地,一般建议数据库提供商的驱动必须小一点,从而保证在加载多个驱动后不会占用太多的内存。

       Driver接口中共有以上六个方法。其中红色的两个相对很重要,它是供DriverManager调用的,其它四个很简单的方法!下面简单讲述前两个方法的意义!

       Connection connect(String url, java.util.Properties info) throws SQLException方法是数据库提供商的驱动必须实现的方法,它主要是使用指定的URL和与具体提供商相关的信息建立一个连接。

boolean acceptsURL(String url) throws SQLException方法也是数据库提供商的驱动必须实现的方法,主要判定某个该驱动是否介绍该URL。(一般在建立连接之前调用。详情将DriverManager类)

二、DriverManager

       DriverManager类是整个JDBC的起点!利用它可以创建连接,从而完成后续的操作。在JDBC DriverManager是一个相对比较复杂的类,因此我们按其只能分为几类介绍。本篇将DriverManager中的方法分为3类:1.初始化;2.驱动的注册、查询、取消注册;3.建立连接;4.日志相关。

       下面就看看它的源代码吧!

//DriverManager.java        1.45 05/11/17

package java.sql;

import sun.misc.Service;

import java.util.Iterator;

class DriverInfo {

    Driver         driver;

    Class          driverClass;

    String         driverClassName;

    public String toString() {

     return ("driver[className=" + driverClassName + "," + driver + "]");

    }

}

public class DriverManager {

    // Prevent the DriverManager class from being instantiated.

    private DriverManager(){}

       以上是其代码的前面部分。主要是包的定义、相关文件的导入、类的定义以及一个私有化的构造器――即该类不可以实例化,只可以调用其静态方法,相当于一个工具类――一个管理驱动的工具类!还有一个就是一个辅助类DriverInfo,它包装了驱动类Driver,包含驱动类的类和驱动类的名称。

         下面就开始DriverManager类重要方法的介绍吧!

1.初始化

private static java.util.Vector drivers = new java.util.Vector();    //保存多个驱动的聚集

private static boolean initialized = false;                                              //是否初始化的标记,默认当然是否了

// 真正的初始化方法

    static void initialize() {

        if (initialized) {    return;     }                                   //已经初始化就返回!(初始化了就算了)

        initialized = true;                                                               //设置此标识符,表示已经完成初始化工作

        loadInitialDrivers();                                                           //初始化工作主要是完成所有驱动的加载

        println("JDBC DriverManager initialized");

}

//初始化方法中完成加载所有系统提供的驱动的方法

    private static void loadInitialDrivers() {

        String drivers;

        try {

         drivers = (String) java.security.AccessController.doPrivileged(

              new sun.security.action.GetPropertyAction("jdbc.drivers"));

                                 //得到系统属性"jdbc.drivers"对应的驱动的驱动名(这可是需要许可的哦!)

        } catch (Exception ex) {

            drivers = null;

        }       

        Iterator ps = Service.providers(java.sql.Driver.class);         //从系统服务中加载驱动

        while (ps.hasNext()) {                                                                        //加载这些驱动,从而实例化它们

            ps.next();

        } 

        println("DriverManager.initialize: jdbc.drivers = " + drivers);

        if (drivers == null) {    return;       }                                       //系统属性未指定驱动则返回

        while (drivers.length() != 0) {                                                              //循环过程,讲解见下面

            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 {

                println("DriverManager.Initialize: loading " + driver);

                Class.forName(driver, true, ClassLoader.getSystemClassLoader());       

                                                   //加载这些驱动,下篇会讲解其细节

            } catch (Exception ex) {

                println("DriverManager.Initialize: load failed: " + ex);

            }

        }//end of while

               //系统属性"jdbc.drivers"可能有多个数据库驱动,这些驱动的名字是以“:”分隔开的,

               //上面的过程就是将此以“:”分隔的驱动,依次遍列,然后调用Class.forName依次加载

}

private static Object logSync = new Object();                //对象锁

//下面是一个辅助方法,用于向日志中写入信息!

public static void println(String message) {

     synchronized (logSync) {                        //很重要的一致性编程的方法,见下面

         if (logWriter != null) {                                          //设置日志才可以进行下面的写入信息

              logWriter.println(message);                      //logger中写入信息

              logWriter.flush();

         }

     }

}

//以上蓝色的属性和方法,是一致性编程(Concurent Programming)中的重要方法。

//首先明确我们在向日志写入信息的时候,是可以调用其它非写入日志的方法的,

//只是不同的客户不能同时调用该写入方法――一个客户正在写入,其它必须等待写完

//假如我们机械地使用synchronized(this)synchronized该写入方法时,必然会导致效率低

//一般地,当类的中多个方法可以分为多个不同组,这些组的方法互相之间不干扰时,

//可以为每个组指定一个自己的锁,限制同一个方法被多个客户使用,从而保证该方法的

//一致性,保证无必要的synchronized方法!

//关于一致性编程,请多关注博客中的文章

2.驱动的注册、查询、取消注册

//DriverManager 注册指定的驱动。驱动这么注册请阅读下篇!

    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();               //以上填入注册驱动的信息

              drivers.addElement(di);                                                       //将此驱动信息假如驱动聚集中

              println("registerDriver: " + di);

    }

       //

    public static synchronized Driver getDriver(String url) throws SQLException {

        println("DriverManager.getDriver( "" + url + " ")");

        if (!initialized) {      initialize();        }                 //同样必须先初始化

        //本地方法,得到调用此方法的类加载器

               ClassLoader callerCL = DriverManager.getCallerClassLoader();            

        // 遍列所有的驱动信息,返回能理解此URL的驱动

        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;

            }

            try {

                println("    trying " + di);

                                  if (di.driver.acceptsURL(url)) {                                //驱动能理解此URL时,返回此驱动

                    println("getDriver returning " + di);

                    return (di.driver);

                }

            } catch (SQLException ex) {

                                 // Drop through and try the next driver.

            }

        }

        println("getDriver: no suitable driver");

        throw new SQLException("No suitable driver", "08001");

    }

//DriverManager 中取消注册某个驱动。Applet仅仅能够取消注册从它的类加载器加载的驱动

    public static synchronized void deregisterDriver(Driver driver) throws SQLException {

              ClassLoader callerCL = DriverManager.getCallerClassLoader();

              println("DriverManager.deregisterDriver: " + driver);     

              int i;

              DriverInfo di = null;

              for (i = 0; i < drivers.size(); i++) {

                 di = (DriverInfo)drivers.elementAt(i);

                  if (di.driver == driver) {break;    }                //找到了某个驱动则返回,同时返回i

              }

         if (i >= drivers.size()) {                                                         //全部遍列完,度没有找到驱动则返回

             println("    couldn't find driver to unload");

             return;

         }     

     //找到此驱动,但调用者不能加载此驱动,则抛出异常

     if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {

         throw new SecurityException();

     }     

     // 在以上所有操作后,可以删除此驱动了

     drivers.removeElementAt(i);     

    }

    //得到当前所有加载的JDBC驱动的枚举**

    public static synchronized java.util.Enumeration getDrivers() {

        java.util.Vector result = new java.util.Vector();

        if (!initialized) {     initialize();      }              //该类没有初始化时,必须完成初始化工作

                                                                                                           //详情请阅读初始化部分

               ClassLoader callerCL = DriverManager.getCallerClassLoader();    //得到当前类的类加载器 

        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;

            }

            result.addElement(di.driver);                       //

分享到:
评论

相关推荐

    JDBC 驱动加载过程分析

    在Java数据库连接(JDBC)中,驱动加载过程是连接到特定数据库的关键步骤。Oracle JDBC驱动是用于与Oracle数据库交互的Java驱动程序。本篇将深入解析Oracle JDBC驱动的加载过程,帮助理解如何通过JDBC建立数据库连接...

    JDBC中驱动加载的过程分析(上)

    JDBC驱动加载的过程涉及`Driver`接口的实现和`DriverManager`类的使用。通过这些机制,JDBC能够实现数据库驱动程序的动态加载和管理,从而支持多种不同的数据库系统,使得Java应用程序具有高度的数据库独立性和灵活...

    JDBC中驱动加载的过程分析(下)

    在深入探讨JDBC驱动加载的过程之前,我们先简要回顾一下上文提到的JDBC(Java Database Connectivity)是什么。JDBC是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的...

    JDBC驱动加载分析

    ### JDBC驱动加载分析 #### 背景与概念 在Java开发中,JDBC (Java Database Connectivity) 是一种用于执行SQL语句的标准Java API,它由一组用Java语言编写的类和接口组成。JDBC提供了Java应用程序与各种类型的关系...

    impala数据库JDBC驱动集

    2. 加载JDBC驱动: ```java Class.forName("com.cloudera.impala.jdbc41.Driver"); ``` 这里的类名取决于实际使用的JDBC驱动版本。 3. 创建数据库连接: ```java String url = "jdbc:impala://&lt;impala_server&gt;:...

    JDBC-impala驱动包

    这两个文件是Cloudera官方提供的Impala JDBC驱动程序,它们允许Java应用程序通过JDBC接口与Impala进行通信,执行SQL查询、数据操作和管理任务。 1. ImpalaJDBC41.jar: 这个版本的驱动支持JDBC 4.1规范,是基于Java ...

    java高手的文章合集3/3

    JDBC中驱动加载的过程分析(上).pdf JDBC中驱动加载的过程分析(下).pdf 从大学教育与工作的差距谈源代码阅读的必要.pdf 给学习J2EE的朋友一些值得研究的开源项目.pdf 教你建立简单JDBC程序.pdf 六步教你学会简单...

    JDBC驱动无法连接的解决办法

    JDBC驱动无法连接的解决办法 在 Java 编程中,使用 JDBC 驱动连接数据库是一个非常常见的操作,但是有时候我们可能会遇到 JDBC 驱动无法连接的问题。今天,我们就来讨论一下这种情况下该如何解决。 症状 在使用 ...

    SQLserver2005最新JDBC驱动

    在"sqljdbc_1.1"这个压缩包文件中,很可能包含了SQL Server 2005的JDBC驱动的1.1版本。这个版本可能包含以下关键知识点: 1. **驱动类型**:根据JDBC规范,驱动通常分为4种类型,Type 1至Type 4。SQL Server 2005的...

    适用SQL Server 2016版本的数据库加载驱动包——sqljdbc42.jar

    在Java应用程序中与SQL Server 2016交互,通常需要依赖特定的数据库驱动程序,这就是`sqljdbc42.jar`的角色。 `sqljdbc42.jar`是一个Java数据库连接(JDBC)驱动包,专为与SQL Server 2016配合使用而设计。JDBC是...

    小白看得懂的MySQL JDBC 反序列化漏洞分析 - 先知社区1

    在源代码分析中,作者发现了一个可能的入口点,即在处理结果集时,驱动会尝试将结果转换为Java对象,这可能包括反序列化过程。 为了利用这个漏洞,攻击者需要了解Java序列化的机制,以及如何构造能够控制反序列化...

    kettle链接SQL server驱动 sqljdbc

    总的来说,了解并正确使用SQL JDBC驱动对于Kettle与SQL Server的集成至关重要,特别是对于那些在Java环境中进行数据处理和分析的项目。正确选择和配置驱动,可以确保数据迁移、数据清洗和其他数据操作的顺利进行。在...

    连接sqlServer的jdbc驱动jar包

    在本案例中,我们讨论的是用于连接SQL Server的JDBC驱动jar包。 标题"连接sqlServer的jdbc驱动jar包"指的是这个压缩包内包含了一个或多个jar文件,这些jar文件是Java应用程序用来建立与SQL Server数据库连接的必备...

    matlab开发-下载并配置jdbc驱动程序

    % 加载JDBC驱动 driverClass = 'com.mysql.jdbc.Driver'; classForName(driverClass); % 建立连接 conn = java.sql.DriverManager.getConnection(url, username, password); ``` 这段代码尝试连接到本地的...

    EXCEL-JDBC驱动

    在Java中,JDBC驱动扮演着桥梁的角色,将应用程序与各种类型的数据库系统连接起来。对于Excel,JDBC驱动通常由Apache POI项目等第三方库提供,如JExcelAPI或Apache POI的HSSF和XSSF组件。这些库解析Excel文件格式,...

    CDH6.3.2的Hive JDBC驱动

    在实际应用中,用户需要在Datart的配置中指定这些JDBC驱动的路径,以便系统能够正确识别和加载。使用非standalone模式的Hive JDBC驱动,意味着用户可以根据需求选择需要的组件,降低依赖性,提高系统的稳定性和灵活...

    JDBC驱动插件

    使用这些JDBC驱动插件时,开发者需要按照JDBC规范在程序中加载对应的驱动,通常是通过`Class.forName()`方法指定驱动类的全限定名,然后使用`DriverManager.getConnection()`方法创建数据库连接。之后,可以创建...

    hana jdbc ngdbc.jar com.sap.db.jdbc.Driver

    同时,由于 SAP HANA 是一个高性能、内存中的数据库系统,因此使用 JDBC 驱动可以充分利用其并发处理能力和实时分析能力。 总的来说,了解并熟练使用 SAP HANA JDBC 驱动对于任何需要与 HANA 数据库进行交互的 Java...

    x-pack-sql-jdbc.rar

    开发者可以利用X-Pack SQL JDBC驱动在Java Web应用、数据分析工具(如Tableau、Excel)或者ETL(提取、转换、加载)流程中,无缝对接Elasticsearch,简化数据处理过程。 总结,X-Pack SQL JDBC驱动为Elasticsearch...

    数据库sql server2005和2000的驱动包-sql-jdbc

    SQL Server是Microsoft公司推出的关系型数据库管理系统,广泛应用于企业级数据存储和管理。在Java编程中,通过JDBC...在使用过程中,理解JDBC驱动的工作原理以及如何正确配置和使用,是确保应用程序稳定运行的关键。

Global site tag (gtag.js) - Google Analytics