刚才无意中看到几篇讲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)。
分享到:
相关推荐
DriverManager提供的符号链查看功能可以帮助开发者追踪驱动的加载顺序,以及它们如何与其他内核组件交互,这对于理解和调试复杂的驱动生态系统至关重要。 5. **物理内存浏览** 为了进行低级别的内存调试和分析,...
- 安全性检查:对于不可信的驱动,`DriverManager`只在加载驱动的类加载器与发起连接请求的代码相同的情况下使用。 - 如果多个驱动都能连接,`DriverManager`会选择第一个成功建立连接的驱动,这意味着驱动的测试...
总结来说,虽然`DriverManager`类自身不直接提供日志控制,但我们可以通过调整数据库驱动的配置、使用Java内置的日志框架或者集成第三方日志库来实现日志输出的控制。理解这些机制有助于我们在开发过程中更好地监控...
它维护了一个驱动程序列表,当应用程序请求与数据库建立连接时,`DriverManager`会根据提供的URL找到合适的驱动程序,并使用该驱动程序创建连接。 **registerDriver()** 方法是`DriverManager`类的一个静态方法,它...
驱动管家DriverManager v1.0中文绿色免费版是一款专为用户设计的系统工具,主要功能集中在硬件驱动程序的管理上,包括驱动升级、驱动备份和驱动还原三个方面。这些功能对于保持计算机系统的稳定性和优化硬件性能至关...
**达蒙数据库与JDBC驱动概述** 达蒙数据库(Dameng Database)是一款源自中国的高性能、高可用性的关系型数据库管理系统,特别适用于企业级应用。它支持标准的SQL语法,提供了丰富的数据类型和强大的事务处理能力,...
安装JDBC驱动后,可以通过`Class.forName()`方法加载驱动,并使用`DriverManager.getConnection()`建立与MySQL服务器的连接。 2. **Oracle JDBC驱动**: Oracle数据库是商业级的、高性能的数据库系统。Oracle提供...
在Java中,JDBC驱动程序提供了一个标准的API,使得开发人员能够使用SQL语句与各种数据库进行交互。这个压缩包包含了用于连接到SQL Server 2005的Java驱动以及JDTS驱动,它们都是实现JDBC规范的不同类型。 首先,让...
在Java环境中,为了能够与SQL Server进行数据交互,我们需要一个兼容的 JDBC (Java Database Connectivity) 驱动程序,通常以jar(Java Archive)文件的形式存在。本文将深入探讨SQL Server驱动jar的相关知识点,...
Oracle驱动包和MySQL驱动包是数据库连接的重要组成部分,它们使得Java或其他编程语言能够与数据库进行交互,执行查询、更新和事务处理等操作。在本文中,我们将深入探讨这两个驱动包的特点、用途以及如何在实际开发...
`mysql-connector-java-8.0.22.zip`包含的是适用于MySQL 8.2的Java驱动,8.0.x版本的驱动与MySQL 8.x服务器版本相匹配。解压后,同样将`mysql-connector-java-x.x.x.jar`文件添加到Java项目类路径,以便进行数据库...
这些JDBC驱动文件的使用方式大致相同,都需要在Java程序中通过`Class.forName()`加载对应的驱动类,然后使用`DriverManager.getConnection()`方法创建数据库连接。例如: ```java // 加载驱动 Class.forName(...
JDBC驱动加载是一个关键步骤,它决定了Java应用程序能否成功地与数据库建立连接。在本例中,我们将探讨sun提供的JDBC-ODBC桥接驱动的加载过程。这种驱动方式通常用于像Microsoft Access这样的数据库,需要配置数据源...
本文将详细介绍关于SQL Server 2000、2005以及MySQL数据库的驱动,以及如何使用这些驱动来建立数据库连接。 首先,让我们关注SQL Server 2000和2005的驱动。微软的SQL Server是一款广泛使用的商业关系型数据库管理...
在Java开发环境中,为了实现Java程序与神通数据库的交互,我们需要使用特定的Java连接驱动,也就是JDBC驱动。本压缩包“神通数据库java连接驱动.zip”中包含了用于Java应用程序连接神通数据库所需的驱动文件。 首先...
MySQL驱动jar包是Java应用程序与MySQL数据库进行交互的重要组件,它是Java Database Connectivity (JDBC) 驱动的一部分。在Java编程中,当你需要连接到MySQL数据库执行查询、更新或其他数据库操作时,这个驱动程序...
MySQL驱动包是用于Java应用程序与MySQL数据库之间进行通信的关键组件,它遵循Java Database Connectivity (JDBC) API标准。在Java编程中,当你需要连接到MySQL数据库执行查询、更新或者其他数据库操作时,就需要引入...
该库主要包含两个导出函数,用于与驱动相关的操作,如安装、启动、停止和卸载。以下是这两个关键函数的详细说明: 1. `GYWDKSetDllPath` 函数: - 函数原型:`__declspec(dllexport) int GYWDKSetDllPath(const ...
这段代码首先加载了JDBC驱动(`Class.forName("com.mysql.jdbc.Driver")`),然后通过`DriverManager.getConnection()`方法建立与MySQL数据库的连接。请注意,随着版本的更新,新版本的驱动可能需要使用`...
Kingbase_v8_R3JDBC驱动属于Type 4,它是纯Java实现的,直接与数据库服务器通信,无需依赖特定的数据库API或者中间层软件。 使用Kingbase_v8_R3JDBC驱动时,开发者需要注意以下几点: 1. 确保Java环境和JDBC驱动...