Получение java.lang.NoClassDefFoundError: Не удалось инициализировать исключение класса oracle.jdbc.OracleDriver - PullRequest
0 голосов
/ 02 марта 2019

Я вижу странное поведение при попытке доступа к базе данных с помощью драйверов 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

Итак, я вижу, что имя драйвера, которое я пытаюсьget is 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 голосов
/ 03 марта 2019

Итак, я провел дальнейшее расследование следующим образом.Я написал минимальный завершенный пример:

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, и все четыре варианта пути к классам были выполнены успешно.

0 голосов
/ 02 марта 2019

Это не полный ответ, но, похоже, это проблема загрузки класса в сочетании с автоматической загрузкой драйвера.

Когда вы явно используете 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) перед (?) Регистрацией себя.И что еще хуже, он делает это из конструктора драйвера вместо статического инициализатора, что потенциально может привести к тупику загрузки драйвера.Правильный драйвер должен вызывать DriverManager.registerDriver из статического инициализатора, как указано в разделе 9.2 JDBC 4.3:

Драйверы JDBC должны реализовывать интерфейс Driver, а реализация должна содержать статический инициализатор, который будетвызываться, когда драйвер загружен.Этот инициализатор регистрирует новый экземпляр самого себя с помощью DriverManager, как показано в ПРИМ. КОДА 9-1.

public class AcmeJdbcDriver implements java.sql.Driver {
    static {
        java.sql.DriverManager.registerDriver(new AcmeJdbcDriver());
    }
    ... 
} 

ПРИМЕР КОДА 9-1 Пример статического инициализатора для драйвера, реализующего java.sql.Driver

Когда загружена реализация Driver, статический инициализатор автоматически зарегистрирует экземпляр драйвера.

Поскольку вызывается DriverManager.getDrivers, он автоматически загружает драйверы в путь к классам в META-INF/service/java.sql.Driver файлов (и тех, что в системном свойстве jdbc.drivers).

Похоже, что драйвер Oracle JDBC был обнаружен и загружен таким образом, но затем проверка, доступен ли драйвер в текущем загрузчике классов в isDriverAllowed, завершается неудачей с NoClassDefFoundError(проверка перехватывает исключения, но не ошибки, и, возможно, должна).

В качестве обходного пути вы должны либо удалить драйвер Oracle JDBC из пути к классам, либо выяснить, почему он недоступен в текущемзагрузчик классов.

В качестве дополнительной диагностики попробуйте позвонить DriverManager.getDrivers(), Class.forName("oracle.jdbc.Driver) или даже new oracle.jdbc.Driver() в своем коде и посмотреть, что произойдет.

Вы также можете проверитьверсия вашего драйвера Sybase, и если есть более новая версия, которая не выполняет эту проверку, хотя это может просто привести к возникновению ошибки в другом месте вашего кода.

...