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 方法
getConnection
和getDrivers
已得到增强,以支持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()
、registerDriver
或 getDriver()
中的任何一个。您只需拨打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的主要内容,如果未能解决你的问题,请参考以下文章
JDBC Class.forName 与 DriverManager.registerDriver
Class.forName(JDBC_DRIVER) 不再需要?
错误:java.lang.ClassNotFoundException:com.mysql.jdbc.Driver [重复]