Java 驱动程序类在JDBC4中是如何定位的

Java 驱动程序类在JDBC4中是如何定位的,java,database,jdbc,Java,Database,Jdbc,JDBC第4版中的一个重要新增功能是,您不必显式加载 通过调用Class.forName驱动程序。当应用程序首次尝试连接数据库时,DriverManager会自动加载在中找到的驱动程序 应用程序CLASSPATH 我的问题是怎么做?如果类路径中有多个驱动程序怎么办? 我能猜到的一件事是,在解析连接URL时,可以确定所需的驱动程序是JDBC还是ODBC,但是如何从多个兼容JDBC的驱动程序中说出要为我使用的数据库选择哪个驱动程序呢?(假设我正在使用MySql,我需要MySql连接器驱动程序)。JV

JDBC第4版中的一个重要新增功能是,您不必显式加载 通过调用
Class.forName
驱动程序。当应用程序首次尝试连接数据库时,
DriverManager
会自动加载在中找到的驱动程序 应用程序
CLASSPATH

我的问题是怎么做?如果类路径中有多个驱动程序怎么办?


我能猜到的一件事是,在解析连接URL时,可以确定所需的驱动程序是JDBC还是ODBC,但是如何从多个兼容JDBC的驱动程序中说出要为我使用的数据库选择哪个驱动程序呢?(假设我正在使用MySql,我需要MySql连接器驱动程序)。JVM中是否存在此类数据库驱动程序的静态映射?

有关JDBC4驱动程序加载的一些信息来自:

调用getConnection方法时,DriverManager将 尝试从以下JDBC驱动程序中找到合适的驱动程序: 在初始化时加载,并且使用 与当前应用程序相同的类装入器

DriverManager方法getConnection和getDrivers已被删除 增强以支持JavaSE服务提供程序机制(SPM)。 根据SPM,服务被定义为一组众所周知的 接口和抽象类,而服务提供者是特定的 服务的实现。它还指定服务 提供程序配置文件存储在META-INF/services中 目录JDBC4.0驱动程序必须包含该文件 META-INF/services/java.sql.Driver。此文件包含文件名 JDBC驱动程序对java.sql.driver的实现。例如,加载 连接到ApacheDerby数据库的JDBC驱动程序 META-INF/services/java.sql.Driver文件将包含以下内容 条目:

现在来回答你的问题

我的问题是怎么做?如果系统中有多个驱动程序呢 类路径


作为类加载器规则,首先找到的任何类都将被加载,如果已经加载,则不会被类加载器重新加载。

每个符合JDBC 4的驱动程序在其jar中都有一个名为
META-INF/services/java.sql.driver
的文件,在该文件中它将列出
java.sql.driver
的实现。当您请求连接时,
DriverManager
将使用查找类路径中
META-INF/services/java.sql.Driver
的所有(!)副本,然后加载列出的所有类。加载
java.sql.Driver
类时,它必须向
DriverManager
注册自身,因此
DriverManager
使用服务加载器加载所有类,并且每个
驱动程序
实现都注册自身

当您从
DriverManager
请求连接时,
DriverManager
将迭代所有注册的驱动程序,请求它们连接
。驱动程序将使用JDBC url检查它是否支持协议(例如Jaybird/Firebird JDBC检查url是否以
“JDBC:firebirdsql:
”JDBC:Firebird:
开头)。如果驱动程序不支持该协议,它将返回
null
,如果它确实支持该协议,它将返回已建立的连接,或者抛出
SQLException
(例如,如果您在URL中出错,或者无法连接)。如果所有驱动程序返回
null
(没有一个支持该协议),则
DriverManager
将抛出
SQLException
,错误为
“找不到合适的驱动程序”


因此,在类路径上有多个驱动程序并不重要,只要它们支持不同的协议,但是如果同一数据库有多个驱动程序(或者至少:相同的协议前缀),它将使用驱动程序列表中的第一个。根据Java版本的不同,如果该驱动程序因出现
SQLException
而失败,它将继续使用下一个驱动程序(至少是Java 5及更高版本),或者停止尝试并抛出异常(我相信这是在Java 1.4或更早版本中出现的)。

您的问题答案将从Java.sql.DriverManager Java类中获得,方法loadInitialDrivers

drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
    public String run() {
                return System.getProperty("jdbc.drivers");
            }
        });  

你为什么需要一个驱动程序?否则你将如何连接到数据库。传统上我们做Class.ForName(driver)。@atamanroman我没什么要解释的,不要用你的术语。我们能列出所有已经在机器上注册的驱动程序吗?@Joseph_Marzbani是的,检查API,特别是
drivers()
getDrivers()
方法。
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
    public String run() {
                return System.getProperty("jdbc.drivers");
            }
        });  
    String[] driversList = drivers.split(":");
    println("number of Drivers:" + driversList.length);
    for (String aDriver : driversList) {
        try {
            println("DriverManager.Initialize: loading " + aDriver);
            Class.forName(aDriver, true,
                    ClassLoader.getSystemClassLoader());
        } catch (Exception ex) {
            println("DriverManager.Initialize: load failed: " + ex);
        }