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
方法getConnection
和getDrivers
已得到增强,以支持 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("Something") 和 Class.forName("Something").newInstance() 之间的区别; [复制
Class.forName() 初始化Thread.currentThread().getContextClassLoader().getResourceAsStream