JDBC Class.forName 与 DriverManager.registerDriver

Posted

技术标签:

【中文标题】JDBC Class.forName 与 DriverManager.registerDriver【英文标题】:JDBC Class.forName vs DriverManager.registerDriver 【发布时间】:2011-07-25 22:46:06 【问题描述】:

forName 方法与registerDriver 加载和注册 JDBC 驱动程序有什么区别?

【问题讨论】:

registerDriver 要求驱动程序在编译时可用。在运行时失败(可用性)将导致 NoClassDefFoundError (您通常不想处理)。 Class.forName 表示后期绑定,并且不需要驱动程序在编译时可用。 【参考方案1】:

Class.forName() 与 JDBC 没有直接关系。它只是加载一个类。

大多数 JDBC 驱动程序类通过调用 registerDriver() 在其静态初始化程序中注册自己。

registerDriver() 是您几乎不需要自己调用的真正调用(除非您编写自己的 JDBC 驱动程序)。

请注意,在 JDBC 4 中,如果您的 JDBC 驱动程序是最新的,则您不应该需要其中任何一个,因为可以使用服务定位机制找到驱动程序(即,只需省略像往常一样打电话并打开您的连接)。详情见documentaton of DriverManager

DriverManager 方法getConnectiongetDrivers 已得到增强,以支持Java 标准版服务提供者机制。 JDBC 4.0 驱动程序必须包含文件META-INF/services/java.sql.Driver。该文件包含java.sql.Driver 的JDBC 驱动程序实现的名称。例如,要加载 my.sql.Driver 类,META-INF/services/java.sql.Driver 文件将包含以下条目:

my.sql.Driver

应用程序不再需要使用Class.forName() 显式加载 JDBC 驱动程序。当前使用 Class.forName() 加载 JDBC 驱动程序的现有程序将继续工作而无需修改。

【讨论】:

mysql JDBC Driver source code为例。它在其静态初始化程序中调用registerDriver 好的,但是如果我使用 registerDriver,我必须将类加载到内存中? @xdevel:我不明白你在做什么。如果您想要做的只是连接到数据库并且您拥有足够现代的 JDBC 驱动程序,那么您不需要 Class.forName()registerDrivergetDriver() 中的任何一个。您只需拨打DriverManager.getConnection("jdbc:mysql://localhost") 即可,无需任何其他准备。如果您想做其他事情,请告诉我们那是什么。 好的,请耐心等待 :) 我的问题只是为了更好地了解 JDBC 驱动注册机制。 @Pacerier:是的,我希望会发生这种情况,但我不知道 JDBC 框架会如何应对(我希望它要么忽略第二次调用,要么在第二次调用,无论哪种方式,驱动程序都将被注册)。正如我在答案中所写:除非您正在编写自己的 JDBC 驱动程序,否则真的没有理由自己打电话给registerDriver【参考方案2】:

永远不要手动调用DriverManager.registerDriver() 方法。 JDBC 规范要求驱动程序在加载类时自行注册,并且类通过Class.forName() 加载。在 JDBC 4 中,驱动程序只需位于类路径上即可自动加载。

DriverManager.registerDriver() 手动操作具有潜在危险,因为它实际上会导致驱动程序注册两次。如果您的代码要求您注销驱动程序以防止内存泄漏,那么您最终只会注销一次并保留第二个实例注册。

【讨论】:

如果你调用 register,你将需要调用 deregister(我猜这只是正常的)。 Class.forName() 具有不会取消注册驱动程序的副作用。我记得 tomcat 试图在重新部署 webapp 时取消注册 webapp 加载的驱动程序。 不,Driver 需要自己调用DriverManager.register。如果您查看DriverManager 的来源,调用register 将添加另一个Driver,无论它是否已经注册。同样deregister 只会删除一个实例,无论它被注册了多少次。简短的回答:不要那样做。 @DavidO'Meara,如果 DriverManager.registerDriver() 永远不应该被直接调用,为什么它是一个公共方法? @Pacerier 它是公开的,因为驱动程序实现需要能够调用它来注册自己。【参考方案3】:

除了 Joachim Sauer 已经提到的关于 JDBC 4 驱动程序的内容外,请注意,实际上您通常希望注入 EntityManager (JPA) 或池化数据源(并使用 Spring 的 JdbcTemplate)。

【讨论】:

是的,一个依赖注入框架。例如。您可以使用 Java EE:在应用程序服务器中配置数据库,然后将 EntityManager 注入您的 EJB:docs.oracle.com/javaee/6/tutorial/doc/bnbqw.html#bnbqz 或者您可以使用 Spring:static.springsource.org/spring/docs/current/…

以上是关于JDBC Class.forName 与 DriverManager.registerDriver的主要内容,如果未能解决你的问题,请参考以下文章

java调用Oracle中的存储过程与存储函数

JDBC Class.forName 与 DriverManager.registerDriver

Class.forName(JDBC_DRIVER) 不再需要?

错误:java.lang.ClassNotFoundException:com.mysql.jdbc.Driver [重复]

jdbc注册驱动 class.forName()

转关于Class.forName(“com.mysql.jdbc.Driver”)