12

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

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

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

4

3 回答 3

19

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

当您从 请求连接时DriverManagerDriverManager将遍历所有已注册的驱动程序,要求他们提供Connection. 驱动程序将使用 JDBC url 来检查它是否是它支持的协议(例如 Jaybird/Firebird JDBC 检查 url 是否以"jdbc:firebirdsql:"or开头"jdbc:firebird:")。如果驱动程序不支持该协议,它将返回null,如果它支持该协议,它将返回一个已建立的连接,或者它会抛出一个SQLException(例如,如果您在 URL 中出错,或者它无法连接) . 如果所有驱动程序都返回null(都不支持该协议),那么DriverManager将抛出一个SQLException错误"No suitable driver found for <url>"

因此,只要它们支持不同的协议,类路径上有多个驱动程序并不重要,但是如果同一个数据库有多个驱动程序(或至少:相同的协议前缀),它将使用驱动程序列表中的第一个。根据 Java 版本,如果该驱动程序以SQLException.

于 2013-08-18T08:54:17.723 回答
12

有关 JDBC4 驱动程序加载的一些信息来自:http ://www.onjava.com/2006/08/02/jjdbc-4-enhancements-in-java-se-6.html

当调用 getConnection 方法时,DriverManager 将尝试从初始化时加载的 JDBC 驱动程序和使用与当前应用程序相同的类加载器显式加载的那些 JDBC 驱动程序中找到合适的驱动程序。

DriverManager 方法 getConnection 和 getDrivers 已得到增强,以支持 Java SE 服务提供者机制 (SPM)。根据 SPM,服务被定义为一组众所周知的接口和抽象类,服务提供者是服务的具体实现。它还指定服务提供者配置文件存储在 META-INF/services 目录中。JDBC 4.0 驱动程序必须包含文件 META-INF/services/java.sql.Driver。此文件包含 java.sql.Driver 的 JDBC 驱动程序实现的名称。例如,要加载 JDBC 驱动程序以连接到 Apache Derby 数据库,META-INF/services/java.sql.Driver 文件将包含以下条目:

org.apache.derby.jdbc.EmbeddedDriver

现在来回答你的问题。

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

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

于 2013-08-17T11:06:35.443 回答
0

您的问题的答案将从 java.sql.DriverManager java 类,方法 loadInitialDrivers 中得到。

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

如果程序发现多个 jdbc 驱动程序,它将使用下面的逻辑来获取确切的驱动程序

    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);
        } 
于 2020-08-28T06:20:54.287 回答