【问题标题】:Why we use Class.forName(“oracle.jdbc.driver.OracleDriver”) while connecting to a database?为什么我们在连接数据库时使用 Class.forName(“oracle.jdbc.driver.OracleDriver”)?
【发布时间】:2013-12-03 10:06:36
【问题描述】:

连接数据库时Class.forName("oracle.jdbc.driver.OracleDriver") 的实际用途是什么?为什么我们不能只导入同一个类,而是为什么要加载它。

【问题讨论】:

标签: java jdbc


【解决方案1】:

使用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 允许您发现功能、保留字等,从而允许您创建或生成兼容的查询.

【讨论】:

  • 在 JDBC 发布者希望许可他们的驱动程序并且不允许将他们的驱动程序与软件打包的世界中,我可以看到这种模式将如何有用。
  • 当驱动程序类的 FQN 发生变化时也很有用......就像 MySQL 数据库驱动程序发生至少两次一样。
  • @StephenC 是的,或者考虑一下 MariaDB - IIRC - 最初没有 JDBC 驱动程序,因此您可以使用 MySQL 驱动程序,现在您可以使用 MariaDB 驱动程序。也有一些商业方提供替代驱动程序,并考虑 jTDS 与 SQL Server JDBC 等。
【解决方案2】:

当我们想要执行一个类的静态块而不创建它的对象时,我们可以使用class.forName()Driver 类所做的大部分工作都存在于其静态块中。

现在我们在 JDBC 连接中需要的是让驱动程序注册到DriverManager 并获得与它的连接,所以这可以通过执行静态块来实现,并且不需要创建该类的对象.这种方法将提供更好的性能。

【讨论】:

  • “更好的性能”比什么?只要驱动程序符合 JDBC 4,这与当前默认情况下发生的情况没有什么不同。
【解决方案3】:

有时需要在运行时加载一个类。即,任何类都可以在执行 java 应用程序时动态加载到内存位置。 Class.forName 用于在运行时加载任何给定的类(在双引号内作为字符串)。例如,当我们使用 IDE 时,我们会看到一个 GUI 构建器,它允许我们拖放按钮、文本字段等。这种拖放机制在内部需要在运行时加载某些类。

在Class.forName(sun.jdbc.odbc.JdbcOdbcDriver)中,Class属于包java.lang.ClassforName()java.lang.Class的静态方法。 JDBC 驱动程序(字符串)将在运行时动态加载到类中,forName 方法包含静态块,该块创建驱动程序类对象并自动注册到DriverManager 服务。由于forName()是静态的,所以我们用类名(Class)来称呼它。

【讨论】:

    【解决方案4】:

    这是一种传统方式。导入类你会有额外的依赖

    来自 Java 教程:

    在以前的 JDBC 版本中,要获得连接,您首先必须 通过调用方法 Class.forName 来初始化 JDBC 驱动程序。这 方法需要 java.sql.Driver 类型的对象。每个 JDBC 驱动程序 包含一个或多个实现接口的类 java.sql.Driver.

    ...

    在您的班级中找到的任何 JDBC 4.0 驱动程序 路径会自动加载。 (但是,您必须手动加载任何 使用 Class.forName 方法的 JDBC 4.0 之前的驱动程序。)

    【讨论】:

      【解决方案5】:

      使用Class.forName("") 而不是直接引用类的几个原因:

      1. 使用Class.forName("") 可以更明显地控制在代码中首次尝试加载指定类的确切位置。如果在该代码运行时该类不存在于类路径中,这使得代码将在何处失败(抛出异常)变得更加明显。

      2. 如果您只是导入该类,然后在代码中引用它,那么如果该类不存在,代码将在何处引发异常就变得不太明显了。

      3. 另外,使用Class.forName("") 是一种绕过潜在编译时限制的方法。例如,如果编译代码的人(例如,出于许可或知识产权原因)无法访问 oracle.jdbc.driver.OracleDriver 类,他们可能会发现通过以下方式编译引用该类的代码更容易Class.forName("") 而不是直接。

      4. 如果您不需要使用指定类的任何方法、字段或内部类,那么Class.forName("") 可能是最清楚的表达方式,即唯一需要的就是加载类(并且它的静态初始化程序运行),仅此而已。

      我认为 Class.forName 与直接引用类没有任何不同的功能行为。它默认使用调用类的类加载器,它应该与直接引用类时使用的类加载器相同。 Class.forName("") 有一些重载,可让您更多地自定义类加载行为。

      【讨论】:

        猜你喜欢
        • 2011-12-24
        • 1970-01-01
        • 2016-01-12
        • 2018-05-08
        • 1970-01-01
        • 2014-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多