为什么我们在连接数据库时使用Class.forName(“oracle.jdbc.driver.OracleDriver”)?

时间:2013-11-19 17:57:05

标签: java jdbc

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

7 个答案:

答案 0 :(得分:22)

使用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 Standard Edition Service Provider机制。 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允许您发现允许您创建或生成的功能,保留字等兼容的查询。

答案 1 :(得分:5)

这是一种传统方式。导入类将具有额外的依赖性

来自Java教程:

  

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

     

...

     

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

答案 2 :(得分:4)

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

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

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

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

  4. 如果您不需要使用指定类的任何方法,字段或内部类,那么Class.forName("")可能是最明确的方式来表达唯一需要的是加载类(并使其静态初始化程序运行),而不是其他任何东西。

  5. 我不认为Class.forName表现出与直接引用类不同的功能行为。它默认使用调用类'classloader,它应该是直接引用类时使用的相同类加载器。 Class.forName(“”)有一些重载可以让你自定义类加载行为。

答案 3 :(得分:0)

Class.forName(“oracle.jdbc.driver.OracleDriver”)将类名作为字符串参数并将其加载到内存中。加载类的第二种方法是使用new简单地创建它的实例。第二种方法的缺点是如果你不需要它,新创建的实例将毫无用处。

有一个很好的教程解释JDBC connection basics

答案 4 :(得分:0)

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

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

答案 5 :(得分:-1)

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

现在我们在JDBC连接中需要的是使用DriverManager注册驱动程序并获取与它的连接,这样只需通过获取静态块就可以实现,并且不需要创建对象那个班。这种方法将提供更好的性能。

答案 6 :(得分:-2)

这用于打开一个类,或者换句话说,通过字符串格式的名称来调用它。
例如:

implicit def genericObjectEncoder[A, H <: HList](
  implicit
  generic: LabelledGeneric.Aux[A, H],
  hEncoder: Lazy[JsonObjectEncoder[H]]
): JsonObjectEncoder[A] =
  createObjectEncoder { value =>
    hEncoder.value.encode(generic.to(value))
  }

implicit val cnilEncoder: JsonObjectEncoder[CNil] =
  createObjectEncoder { cnil => throw new RuntimeException("Inconceivable!") }

implicit def coproductEncoder[H, T <: Coproduct](
  implicit
  hEncoder: Lazy[JsonObjectEncoder[H]],
  tEncoder: JsonObjectEncoder[T]
): JsonObjectEncoder[H :+: T] = createObjectEncoder {
  case Inl(h) => hEncoder.value.encode(h)
  case Inr(t) => tEncoder.encode(t)
}

implicit def genericFamilyEncoder[A, C <: Coproduct](
  implicit
  generic: Generic.Aux[A, C],
  cEncoder: Lazy[JsonObjectEncoder[C]]
): JsonEncoder[A] =
  instance { value =>
    cEncoder.value.encode(  generic.to(value) )
  }

它将在com / android / example / MainClass.java包中启动类