`
aids198311
  • 浏览: 58821 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

关于DriverManager与驱动

阅读更多
刚才无意中看到几篇讲DriverManager源码的文章,发现几点没有讲明白的地方。
这里重新说一下:
直接进入正题
Class.forName("com.mysql.jdbc.Driver");

这个玩意做了这些事情:
1.驱动的实现类:com.mysql.jdbc.Driver 里面的static块,调用DriverManger.registerDriver()来        注册自己
2.DriverManger自己初始化(仅第一次调用注册方法的时候调用一次)
3.把驱动封装成对象存到victor里面

第一点,每个驱动的实现类都必须明确的注册自己到DriverManger里面。
而且这个方法大都是放在static块里面的,所以forName一下就会执行了。

第二点,这个初始化并不是初始化com.mysql.jdbc.Driver这个驱动,而是初始化自带的驱动
如:sun.jdbc.odbc.JdbcOdbcDriver。看代码也能发现,初始化与传递进来的驱动一毛钱关系都没有。
    public static synchronized void registerDriver(java.sql.Driver driver)
	throws SQLException {
	if (!initialized) {
            //这里初始化
	    initialize();
	}
   ....................

最后会调用到
 private static void loadInitialDrivers() {
        String drivers;
        try {
             //这里返回的是null
	    drivers = (String) java.security.AccessController.doPrivileged(
		new sun.security.action.GetPropertyAction("jdbc.drivers"));
        } catch (Exception ex) {
            drivers = null;
        }
	 DriverService ds = new DriverService();
         //在这里会初始化odbc驱动
	 java.security.AccessController.doPrivileged(ds);		
         println("DriverManager.initialize: jdbc.drivers = " + drivers);
        if (drivers == null) {
            return;
        }
}

java.security.AccessController.doPrivileged(ds) 这块代码是native的,搞不清除是干嘛的,于是写了一个代码debug看了一下,程序如下:
public static void main(String[] args) {
        DriverManager.setLogWriter(new PrintWriter(System.out));
        try {
            Class.forName("com.mysql.jdbc.ReplicationDriver");
            Class.forName("com.mysql.jdbc.Driver");
            Class.forName("org.apache.commons.dbcp.PoolingDriver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

注册三个驱动程序,并把DriverManger的log输出到控制台,打上断点debug了一下
发现在
java.security.AccessController.doPrivileged(ds)
方法里面,会调用DriverManager.registerDriver,而且传递的参数Driver是sun.jdbc.odbc.JdbcOdbcDriver
所以可以肯定,initialized()方法是用来初始化自带的驱动程序。显然,后面2个驱动的注册,不会再次初始化DriverManager
控制台的输出如下:
引用

JdbcOdbcDriver class loaded
registerDriver: driver[className=sun.jdbc.odbc.JdbcOdbcDriver,sun.jdbc.odbc.JdbcOdbcDriver@1b09468]
registerDriver: driver[className=com.mysql.jdbc.Driver,com.mysql.jdbc.Driver@10e790c]
DriverManager.initialize: jdbc.drivers = null
JDBC DriverManager initialized
registerDriver: driver[className=com.mysql.jdbc.NonRegisteringReplicationDriver,com.mysql.jdbc.NonRegisteringReplicationDriver@1551d7f]
registerDriver: driver[className=org.apache.commons.dbcp.PoolingDriver,org.apache.commons.dbcp.PoolingDriver@b8deef]



顺带说一下ClassLoader
驱动的实现类都是用下面这个classLoader来加载的
    /* Returns the caller's class loader, or null if none */
    private static native ClassLoader getCallerClassLoader();


虽然又是一个native方法,但是顾名思义可以知道,这个方法返回的是调用者的classLoader,如:我在Class A里面调用了DriverManager.getConnection方法,那么驱动类就是由加载A的classLoader来加载。为啥要这样?
看一下DriverManager就明白了。
   public static void main(String[] args) {
        System.out.println(DriverManager.class.getClassLoader());
   }

控制台输出null
表明DriverManager的classLoader是相当NB的bootstrap ClassLoader
而我们自己写的类一般都是由systemClassloader加载的。
如果在DriverManager直接class.forName("com.mysql.jdbc.ReplicationDriver"),就表示要让bootstrap ClassLoader来加载jdk/lib目录下的com.mysql.jdbc.ReplicationDriver,可能么??明显不在那里,而是在classpath目录下。
所以要这么来class.forName("com.mysql.jdbc.ReplicationDriver",true, callerClassLoader)

另外如果getCallerClassLoader()返回了空,则会获取当前线程上下文的classLoader
          if(callerCL == null) {
	      callerCL = Thread.currentThread().getContextClassLoader();
	   }   

ContextClassLoader可以设置,默认的都是systemClassLoader
ContextClassLoader在web容器里面用到的比较多,它可以让父classLoader访问到子的classLoader的class,如这个驱动程序
就是,在父classLoader(bootstrap)加载的类里面,访问到了子classLoader(SystemClassLoader)才能加载的类(com.mysql.jdbc.ReplicationDriver)。
分享到:
评论
2 楼 diyunpeng 2012-06-18  
JdbcOdbcDriver class loaded
registerDriver: driver[className=sun.jdbc.odbc.JdbcOdbcDriver,sun.jdbc.odbc.JdbcOdbcDriver@1b09468]
registerDriver: driver[className=com.mysql.jdbc.Driver,com.mysql.jdbc.Driver@10e790c]
DriverManager.initialize: jdbc.drivers = null
JDBC DriverManager initialized
registerDriver: driver[className=com.mysql.jdbc.NonRegisteringReplicationDriver,com.mysql.jdbc.NonRegisteringReplicationDriver@1551d7f]
registerDriver: driver[className=org.apache.commons.dbcp.PoolingDriver,org.apache.commons.dbcp.PoolingDriver@b8deef]

驱动不是5.1.20吧,在20这个版本上,默认通过服务发现机制就把驱动加载上了。另外
1.   public static synchronized void registerDriver(java.sql.Driver driver)  
2.throws SQLException {  
3.if (!initialized) {  
4.           //这里初始化  
5.    initialize();  
6.}  

这个在DriverManger里面也没有,你的是从哪里找到的?

DriverManager.setLogWriter(new PrintWriter(System.out));  后默认就加载类初始化函数了,就把驱动加载上了,你设置Logger也没用啊。
1 楼 worldmaomao 2011-08-03  
毛哥友情帮你顶顶!

相关推荐

    DriverManager 驱动加载管理程序

    一个自己写的工具程序,包含驱动开发过程中所需的几种常用功能:1、驱动加卸载。2、内核IDT、GDT、符号链信息查看。3、物理内存浏览。4、掩码计算。

    驱动管家DriverManagerv1.0中文绿色免费版

    驱动管家DriverManager有三个功能:驱动升级、驱动备份、驱动还原!是一款针对硬件驱动管理的软件

    sqlserver各版本jdbc驱动.zip

    DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。Driver:驱动程序,会将自身加载到DriverManager中去,并处理相应的请求并返回相应的数据库...

    JDBCTM 指南:入门3 – DriverManager

    内容: 3 – DriverManager3.1 概述DriverManager 类是 JDBC 的管理层,作用于用户和驱动程序之间。它跟踪可用的驱动程序,并在数据库和相应驱动程序之间建立连接。另外,DriverManager 类也处理诸如驱动程序登录时间...

    JDK8及以上版本的odbc驱动

    由于JDK8把ODBC驱动删除了,因此连接access等一些数据库时需要手动下载驱动,这里一起贴上来 public class AccessConnectTest { private static DateFormat df = new SimpleDateFormat("yyyy-MM-dd mm:ss"); ...

    mysql57驱动jar包

    使用8.0.12版本的连接驱动 使用8.0.12及以上版本的连接驱动,在mysql5.7的连接配置上,基本没有太大的出入。...mysql版本与连接驱动的版本有严格的对应关系,一般来说mysql5.7+对应的连接驱动可以使用mysql-connec

    mysql57以上jdbc驱动jar

    MySQL 5.7 是目前非常流行的关系型数据库之一,在 Java 开发中,我们可以通过使用 MySQL 5.7 驱动 Jar 包来连接和操作数据库。它允许我们在 Java 应用程序中连接到 MySQL 数据库,并执行查询、插入、更新和删除等...

    数据库驱动包.rar

    ct=DriverManager.getConnection( url,user,password); System.out.println("连接数据库成功!"); }catch(Exception e) { e.printStackTrace(); System.out.println("连接数据库失败!"); }

    mysql 5.7 57版本以上数据库驱动 jar

    这是MySQL 5.7版本以上...connection = DriverManager.getConnection(url, username, password); 温馨提示:如果你的MySQL 是5.6版本,加载驱动程序代码为 Class.forName("com.mysql.jdbc.Driver");不是这个资源哟~

    数据库驱动

    jdbc驱动包 JDBC Name: Connector/J Home Page: http://www.oracle.com/technology/software/tech/java/ JDBC Ver: (based on Oracle) Download: ...

    Spring Data JDBC与JDBC的区别

     DriverManager:驱动管理  Driver:JDBC驱动  Connection:数据库连接  Statement:语句,执行SQL  PrepareStatement:预编译语句,性能更好  CallableStatement:调用存储过程  ResultSet:结果集,封装了多...

    java连接Access数据库驱动

    java连接Access数据库操做数据库驱动 连接方法: public static Connection getNativeConnection(){ try { if(nativeConnection!=null && !nativeConnection.isClosed()){ return ...

    excel的jdbc驱动

    这是一个JAVA的jdbc驱动包,可以帮助你想操作数据库一样快速操作excel 示例代码: public static void main(String[] vars){ String driver = "com.hxtt.sql.excel.ExcelDriver"; String url = "jdbc:excel:///C:\...

    MySQL驱动jar

    MySQL驱动jar包,已经测过可以用,有需要的可以自行下载,易于开发的特点,包括通过自动注册服务提供商机制,标准化的连接有效性检查和分类的SQLExceptions的基础上可恢复/重试能力和一流的底层错误。 DriverManager...

    webdrivermanager:Selenium WebDriver的自动驱动程序管理

    WebDriverManager是一个库,它可以自动管理所需的驱动程序(例如chromedriver , geckodriver等)。目录动机如果您使用 ,则可能知道要使用某些浏览器(例如Chrome , Firefox , Edge , Opera , PhantomJS或...

    Ms access jdbc驱动

    con = drivermanager.getconnection("jdbc:odbc:driver={microsoft access driver (*.mdb)};dbq=c:/data/access/test1.mdb","dba","sql"); 后面的代码一样。这样你就可以访问access数据库了。 第三个是用sun的...

    MySQL 5.7版本以上数据库的连接驱动jar包

    这是MySQL 5.7版本以上...connection = DriverManager.getConnection(url, username, password); 温馨提示:如果你的MySQL 是5.6版本,加载驱动程序代码为 Class.forName("com.mysql.jdbc.Driver");不是这个资源哟~

Global site tag (gtag.js) - Google Analytics