Class.forName(JDBC_DRIVER) 不再需要?

Posted

技术标签:

【中文标题】Class.forName(JDBC_DRIVER) 不再需要?【英文标题】:Class.forName(JDBC_DRIVER) no longer needed? 【发布时间】:2015-01-29 17:18:37 【问题描述】:

我在这里读过,从 java 6 开始,您不再需要使用以下方法注册 JDBC 驱动程序:

Class.forName(JDBC_DRIVER);

因为 DriverManager 使用位于系统属性 "jdbc.drivers" 中的路径 检索正确的驱动程序。

但是当我执行以下操作时:

System.out.print(System.getProperty("jdbc.drivers"));

null 被打印出来。

您知道为什么我的应用程序可以正常运行吗? ;)

【问题讨论】:

文档中都有解释:docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html 【参考方案1】:

这与系统属性无关。 Java6(和 JDBC4)引入了一个称为“service provider”的概念,其中已知接口的实现可以在启动期间被 JVM 检测到。 DriverManager 会自动注册符合此要求的驱动程序。这就是为什么不再需要 Class.forName() 的原因 - 但前提是驱动程序支持。

如果META-INF目录下的驱动jar文件中有services目录,则启动服务注册。该目录需要包含一个带有接口名称的文本文件,该接口的名称在 JDBC 驱动程序 java.sql.Driver 包含实现类的情况下实现。

【讨论】:

这意味着我所要做的就是指明我的 JDBC jar 实现,对吗?如果我指出更多的 JDBC 实现呢? @user986437 是的,在类路径中添加 JDBC 4 驱动程序就足够了。我没有尝试使用多个驱动程序,但我猜会根据提供的 URL 选择正确的驱动程序(每个驱动程序支持不同的 URL)。 引入该机制的是 JDBC 4 而不是 JDBC 3; docs.oracle.com/javase/8/docs/api/java/sql/… @user986437 多个 JDBC 实现不是问题,只要它们使用不同的 JDBC-protocol url-prefix(例如 jdbc:mysql、jdbc:firebirdsql、jdbc:postgresql 等)。【参考方案2】:

来自DriverManager的Javadocs:

作为其初始化的一部分,DriverManager 类将尝试加载“jdbc.drivers”系统属性中引用的驱动程序类。这允许用户自定义其应用程序使用的 JDBC 驱动程序。例如,在您的 ~/.hotjava/properties 文件中,您可以指定:

jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver

这意味着不需要指定系统属性(正如它所说的DriverManager尝试)。还有另一种自动加载驱动程序的机制,它依赖于自 Java 6 以来的service loading:

DriverManager 方法 getConnectiongetDrivers 已得到增强,以支持 Java 标准版服务提供者机制。 JDBC 4.0 驱动程序必须包含文件META-INF/services/java.sql.Driver。此文件包含 java.sql.Driver 的 JDBC 驱动程序实现的名称。

现在几乎所有的 JDBC 驱动程序都符合这个要求。请注意,DriverManager 不会在内部填充 jdbc.drivers 属性,因此它仍然为空。

【讨论】:

您不应该自己调用registerDriver 方法,它旨在在加载时由JDBC 驱动程序实现本身调用。唯一真正的例外是,如果您使用不注册自身的驱动程序(几乎所有 JDBC 驱动程序在加载时都会自行注册,可能特殊用途(非主流)驱动程序除外)。 “这意味着应该指定系统属性。” - 如果使用 JDBC 4 驱动程序,这是不正确的,问题中描述的行为表明他/她正在使用 JDBC 4 驱动程序. @JeffScottBrown 确实制定得很糟糕。更像是必须指定系统属性才能将其打印为非空 - 现在已更正。

以上是关于Class.forName(JDBC_DRIVER) 不再需要?的主要内容,如果未能解决你的问题,请参考以下文章

Class.forName(Driver.class)

Java中Class.forName()用法详解

Class.forName(Class) 在特定目录中?

Class.forName("Something") 和 Class.forName("Something").newInstance() 之间的区别; [复制

Class.forName() 初始化Thread.currentThread().getContextClassLoader().getResourceAsStream

Class.forName()用法详解