刚才无意中看到几篇讲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)。
分享到:
相关推荐
一个自己写的工具程序,包含驱动开发过程中所需的几种常用功能:1、驱动加卸载。2、内核IDT、GDT、符号链信息查看。3、物理内存浏览。4、掩码计算。
驱动管家DriverManager有三个功能:驱动升级、驱动备份、驱动还原!是一款针对硬件驱动管理的软件
DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。Driver:驱动程序,会将自身加载到DriverManager中去,并处理相应的请求并返回相应的数据库...
内容: 3 – DriverManager3.1 概述DriverManager 类是 JDBC 的管理层,作用于用户和驱动程序之间。它跟踪可用的驱动程序,并在数据库和相应驱动程序之间建立连接。另外,DriverManager 类也处理诸如驱动程序登录时间...
由于JDK8把ODBC驱动删除了,因此连接access等一些数据库时需要手动下载驱动,这里一起贴上来 public class AccessConnectTest { private static DateFormat df = new SimpleDateFormat("yyyy-MM-dd mm:ss"); ...
使用8.0.12版本的连接驱动 使用8.0.12及以上版本的连接驱动,在mysql5.7的连接配置上,基本没有太大的出入。...mysql版本与连接驱动的版本有严格的对应关系,一般来说mysql5.7+对应的连接驱动可以使用mysql-connec
MySQL 5.7 是目前非常流行的关系型数据库之一,在 Java 开发中,我们可以通过使用 MySQL 5.7 驱动 Jar 包来连接和操作数据库。它允许我们在 Java 应用程序中连接到 MySQL 数据库,并执行查询、插入、更新和删除等...
ct=DriverManager.getConnection( url,user,password); System.out.println("连接数据库成功!"); }catch(Exception e) { e.printStackTrace(); System.out.println("连接数据库失败!"); }
这是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: ...
DriverManager:驱动管理 Driver:JDBC驱动 Connection:数据库连接 Statement:语句,执行SQL PrepareStatement:预编译语句,性能更好 CallableStatement:调用存储过程 ResultSet:结果集,封装了多...
java连接Access数据库操做数据库驱动 连接方法: public static Connection getNativeConnection(){ try { if(nativeConnection!=null && !nativeConnection.isClosed()){ return ...
这是一个JAVA的jdbc驱动包,可以帮助你想操作数据库一样快速操作excel 示例代码: public static void main(String[] vars){ String driver = "com.hxtt.sql.excel.ExcelDriver"; String url = "jdbc:excel:///C:\...
MySQL驱动jar包,已经测过可以用,有需要的可以自行下载,易于开发的特点,包括通过自动注册服务提供商机制,标准化的连接有效性检查和分类的SQLExceptions的基础上可恢复/重试能力和一流的底层错误。 DriverManager...
WebDriverManager是一个库,它可以自动管理所需的驱动程序(例如chromedriver , geckodriver等)。目录动机如果您使用 ,则可能知道要使用某些浏览器(例如Chrome , Firefox , Edge , Opera , PhantomJS或...
con = drivermanager.getconnection("jdbc:odbc:driver={microsoft access driver (*.mdb)};dbq=c:/data/access/test1.mdb","dba","sql"); 后面的代码一样。这样你就可以访问access数据库了。 第三个是用sun的...
这是MySQL 5.7版本以上...connection = DriverManager.getConnection(url, username, password); 温馨提示:如果你的MySQL 是5.6版本,加载驱动程序代码为 Class.forName("com.mysql.jdbc.Driver");不是这个资源哟~