获取java.lang.NoClassDefFoundError:无法初始化类oracle.jdbc.OracleDriver异常

时间:2019-03-02 16:34:54

标签: java jdbc sybase

当尝试使用JDBC驱动程序访问数据库时,我看到一些奇怪的行为。这是代码片段:

LOGGER.debug("driver is " + driver);
try {
    Class.forName(driver);
    LOGGER.debug("got driver");
} catch (Throwable t) {
    LOGGER.debug("throwable getting driver " + driver);
    t.printStackTrace(System.out);
    throw t;
}

运行此命令时,这就是我在堆栈跟踪中看到的内容。

08:20:00.417 [main] DEBUG - driver is com.sybase.jdbc4.jdbc.SybDriver
08:20:00.604 [main] DEBUG - throwable getting driver com.sybase.jdbc4.jdbc.SybDriver
java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:398)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:547)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:449)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
        at com.sybase.jdbc4.jdbc.SybDriver.registerWithDriverManager(Unknown Source)
        at com.sybase.jdbc4.jdbc.SybDriver.<init>(Unknown Source)
        at com.sybase.jdbc4.jdbc.SybDriver.<clinit>(Unknown Source)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:315)
        ... my code

因此我可以看到我要获取的驱动程序名称是com.sybase.jdbc4.jdbc.SybDriver,这是正确的,但是由于某种原因,DriverManager正在寻找oracle.jdbc.OracleDriver。

这是怎么回事?这段代码已经运行了好几年了,我能想到的唯一其他相关信息是我最近将这台计算机上的JDK升级到了Open JDK 11。

>java -version
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)

2 个答案:

答案 0 :(得分:1)

这不是一个完整的答案,但似乎与自动驱动程序加载结合在一起是一个类加载问题。

当您显式使用Class.forName加载JDBC驱动程序时,该驱动程序应向java.sql.DriverManager注册自己。

查看堆栈跟踪,具体是:

    at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
    at com.sybase.jdbc4.jdbc.SybDriver.registerWithDriverManager(Unknown Source)
    at com.sybase.jdbc4.jdbc.SybDriver.<init>(Unknown Source)
    at com.sybase.jdbc4.jdbc.SybDriver.<clinit>(Unknown Source)
    at java.base/java.lang.Class.forName0(Native Method)

在(?)自身注册之前,Sybase驱动程序错误地检查了当前注册的驱动程序(使用DriverManager.getDrivers)。更糟糕的是,它是由驱动程序构造函数而不是静态初始化程序完成的,这有可能导致驱动程序加载死锁。行为正确的驱动程序应按照JDBC 4.3第9.2节的规定,从静态初始化程序调用{​​{1}}:

  

JDBC驱动程序必须实现DriverManager.registerDriver接口,并且   实现必须包含将被调用的静态初始化器   驱动程序加载时。该初始化器注册一个新实例   本身带有Driver,如代码示例9-1所示。

DriverManager
     

代码示例9-1用于实现public class AcmeJdbcDriver implements java.sql.Driver { static { java.sql.DriverManager.registerDriver(new AcmeJdbcDriver()); } ... }

的驱动程序的示例静态初始化程序      

在加载java.sql.Driver实现时,静态初始化程序将   自动注册驱动程序实例。

由于调用了Driver,它将自动在DriverManager.getDrivers文件(以及系统属性META-INF/service/java.sql.Driver中的文件)的类路径中加载驱动程序。

看起来发现了Oracle JDBC驱动程序,但是随后检查驱动程序是否在jdbc.drivers的当前类加载器中可用,并且失败了,并显示{{1 }}(检查可以捕获异常,但不能捕获错误,也许应该)。

作为一种解决方法,您应该从类路径中删除Oracle JDBC驱动程序,或者找出为什么它在当前类加载器中不可用。

为进一步诊断,请尝试在代码中调用isDriverAllowedNoClassDefFoundError)甚至是DriverManager.getDrivers(),然后看看会发生什么。

您可能还想检查Sybase驱动程序的版本,如果有较新的版本不进行此检查,尽管这可能只会导致错误在代码的其他地方发生。

答案 1 :(得分:0)

因此,我做了如下进一步调查。我写了一个最小的完整示例:

import java.sql.*;
import java.util.*;

public class TestDrivers {

    public static void main(String[] args) {
        try {
            Enumeration<Driver> driverEnumeration = DriverManager.getDrivers();
            while (driverEnumeration.hasMoreElements()) {
                Driver driver = driverEnumeration.nextElement();
                System.out.println("driver is " + driver.getClass().getName());
            }
        } catch (Throwable t) {
            System.out.println("throwable getting drivers");
            t.printStackTrace(System.out);
            throw t;
        }
    }
}

然后我使用四个不同的类路径运行此示例,结果如下:

  1. 没有驱动程序JAR文件:成功,没有列出驱动程序
  2. 驱动程序JAR文件:jconn4.jar; jtds-1.3.1.jar; ojdbc6-11.1.0.6.0.jar:java.lang.NoClassDefFoundError失败:无法初始化类oracle.jdbc.OracleDriver
  3. 驱动程序JAR文件:jtds-1.3.1.jar; ojdbc6-11.1.0.6.0.jar:成功列出了jTDS和Oracle驱动程序
  4. 驱动程序JAR文件:jconn4.jar; jtds-1.3.1.jar:成功列出了jTDS和Sybase驱动程序

因此,如果同时存在Oracle和Sybase JDBC驱动程序,则会发生一些奇怪的交互。我还尝试了Oracle ojdbc7.jar和ojdbc8.jar文件,结果基本相同。这是完整的堆栈跟踪:

java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:398)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:547)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:449)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
        at com.javamarket.drivers.TestDrivers.main(TestDrivers.java:10)
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:398)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:547)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:449)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
        at com.javamarket.drivers.TestDrivers.main(TestDrivers.java:10)

最后,我在另一台运行JDK 8的计算机上尝试了此操作,并且所有四个类路径版本均成功运行。