【发布时间】:2013-12-03 10:06:36
【问题描述】:
连接数据库时Class.forName("oracle.jdbc.driver.OracleDriver") 的实际用途是什么?为什么我们不能只导入同一个类,而是为什么要加载它。
【问题讨论】:
连接数据库时Class.forName("oracle.jdbc.driver.OracleDriver") 的实际用途是什么?为什么我们不能只导入同一个类,而是为什么要加载它。
【问题讨论】:
使用Class.forName() 背后的基本思想是加载一个JDBC 驱动程序实现。 (普通)JDBC 驱动程序必须包含一个静态初始化程序,该初始化程序使用java.sql.DriverManager 注册驱动程序实现的实例:
JDBC 驱动程序必须实现
Driver接口,并且该实现必须包含一个静态初始化程序,该初始化程序将在加载驱动程序时调用。这个初始化器用DriverManager注册一个自己的新实例
(来自 JDBC 4.1,第 9.2 节)
然而,从 JDBC 4.0 开始,有一种注册驱动程序的新方法:JDBC 驱动程序的 jar 需要包含一个文件 /META-INF/services/java.sql.Driver,其中包含该 jar 中 java.sql.Driver 实现的名称。当您使用DriverManager 创建连接时,它将使用java.util.ServiceLoader 枚举类路径中的所有/META-INF/services/java.sql.Driver 文件并加载所有驱动程序以便它们被注册。
DriverManager.getConnection方法已得到增强,可支持 Java 标准版服务提供者机制。 JDBC 4.0 驱动程序必须包含文件META-INF/services/java.sql.Driver。此文件包含 JDBC 驱动程序实现的名称java.sql.Driver。
(来自 JDBC 4.1,第 9.2.1 节)
以这种方式加载驱动程序的原因是,它允许您将应用程序与其使用的驱动程序(和数据库)分离。这意味着您无需任何驱动程序即可编写、编译甚至分发应用程序,您只需要使用java.sql(和javax.sql)包中提供的接口——它是Java的一部分——无需访问实现直接。
然后应用程序的用户将一个有效的 JDBC 驱动程序添加到类路径(并配置连接字符串之类的东西),以便应用程序可以真正连接到数据库。在 JDBC 4.0 之前,用户必须指定驱动程序名称,以便应用程序可以使用 Class.forName 加载它,使用符合 JDBC 4.0 的驱动程序和 Java 6 或更高版本,此发现是自动的。
当您从字面上使用Class.forName("oracle.jdbc.driver.OracleDriver") 加载驱动程序时,可能感觉有点矫枉过正,但如果您记住它也可能是从配置文件(或用户输入)中提取的字符串,您可能会开始理解为什么会这样太强大了。
当然,这种驱动程序独立性不是 100%,尤其是在您的应用程序使用供应商特定 SQL 时。但理论是您的应用程序可以独立于数据库。 JDBC 还提供了一些额外的机制来解决这个问题,例如 JDBC 转义以提供驱动程序转换为特定语法的通用语法,DatabaseMetaData 允许您发现功能、保留字等,从而允许您创建或生成兼容的查询.
【讨论】:
当我们想要执行一个类的静态块而不创建它的对象时,我们可以使用class.forName()。 Driver 类所做的大部分工作都存在于其静态块中。
现在我们在 JDBC 连接中需要的是让驱动程序注册到DriverManager 并获得与它的连接,所以这可以通过执行静态块来实现,并且不需要创建该类的对象.这种方法将提供更好的性能。
【讨论】:
有时需要在运行时加载一个类。即,任何类都可以在执行 java 应用程序时动态加载到内存位置。 Class.forName 用于在运行时加载任何给定的类(在双引号内作为字符串)。例如,当我们使用 IDE 时,我们会看到一个 GUI 构建器,它允许我们拖放按钮、文本字段等。这种拖放机制在内部需要在运行时加载某些类。
在Class.forName(sun.jdbc.odbc.JdbcOdbcDriver)中,Class属于包java.lang.Class,forName()是java.lang.Class的静态方法。 JDBC 驱动程序(字符串)将在运行时动态加载到类中,forName 方法包含静态块,该块创建驱动程序类对象并自动注册到DriverManager 服务。由于forName()是静态的,所以我们用类名(Class)来称呼它。
【讨论】:
这是一种传统方式。导入类你会有额外的依赖
来自 Java 教程:
在以前的 JDBC 版本中,要获得连接,您首先必须 通过调用方法 Class.forName 来初始化 JDBC 驱动程序。这 方法需要 java.sql.Driver 类型的对象。每个 JDBC 驱动程序 包含一个或多个实现接口的类 java.sql.Driver.
...
在您的班级中找到的任何 JDBC 4.0 驱动程序 路径会自动加载。 (但是,您必须手动加载任何 使用 Class.forName 方法的 JDBC 4.0 之前的驱动程序。)
【讨论】:
使用Class.forName("") 而不是直接引用类的几个原因:
使用Class.forName("") 可以更明显地控制在代码中首次尝试加载指定类的确切位置。如果在该代码运行时该类不存在于类路径中,这使得代码将在何处失败(抛出异常)变得更加明显。
如果您只是导入该类,然后在代码中引用它,那么如果该类不存在,代码将在何处引发异常就变得不太明显了。
另外,使用Class.forName("") 是一种绕过潜在编译时限制的方法。例如,如果编译代码的人(例如,出于许可或知识产权原因)无法访问 oracle.jdbc.driver.OracleDriver 类,他们可能会发现通过以下方式编译引用该类的代码更容易Class.forName("") 而不是直接。
如果您不需要使用指定类的任何方法、字段或内部类,那么Class.forName("") 可能是最清楚的表达方式,即唯一需要的就是加载类(并且它的静态初始化程序运行),仅此而已。
我认为 Class.forName 与直接引用类没有任何不同的功能行为。它默认使用调用类的类加载器,它应该与直接引用类时使用的类加载器相同。 Class.forName("") 有一些重载,可让您更多地自定义类加载行为。
【讨论】: