尝试使用JDBC驱动程序访问数据库时,我看到一些奇怪的行为。这是代码片段:
LOGGER.debug(“驱动程序是”+驱动程序);尝试{ 的Class.forName(驱动器); 记录仪….
所以我做了一些进一步的调查如下。我写了一个最小的完整例子:
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; } } }
然后我用四个不同的类路径运行这个例子,结果如下:
因此,如果存在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的另一台机器上尝试了这一点,并且所有四个类路径变体都成功运行。
这不是一个完整的答案,但它似乎是一个类加载问题与自动驱动程序加载相结合。
当您明确使用时 Class.forName 要加载JDBC驱动程序,驱动程序应该注册自己 java.sql.DriverManager 。
Class.forName
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 从JDBC 4.3第9.2节中指定的静态初始化程序:
DriverManager.getDrivers
DriverManager.registerDriver
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 加载实现,静态初始化器将 自动注册驱动程序的实例。
JDBC驱动程序必须实现 Driver 界面,和 实现必须包含将被调用的静态初始化程序 当驱动程序加载时。此初始化程序注册一个新实例 与...有关 DriverManager ,如代码示例9-1所示。
Driver
DriverManager
public class AcmeJdbcDriver implements java.sql.Driver { static { java.sql.DriverManager.registerDriver(new AcmeJdbcDriver()); } ... }
代码示例9-1驱动程序实现的静态初始化程序示例 java.sql.Driver
java.sql.Driver
当一个 Driver 加载实现,静态初始化器将 自动注册驱动程序的实例。
因为 DriverManager.getDrivers 被调用,它将自动加载类路径中的驱动程序 META-INF/service/java.sql.Driver 文件(以及系统属性中的文件) jdbc.drivers )。
META-INF/service/java.sql.Driver
jdbc.drivers
看起来像是发现了Oracle JDBC驱动程序 的 和 强> 以这种方式加载,但检查驱动程序是否在当前类加载器中可用 isDriverAllowed 失败了 NoClassDefFoundError (检查捕获异常,但没有错误,也许它应该)。
isDriverAllowed
NoClassDefFoundError
作为解决方法,您应该从类路径中删除Oracle JDBC驱动程序,或者找出它在当前类加载器中不可用的原因。
作为进一步诊断,尽量打电话 DriverManager.getDrivers() , Class.forName("oracle.jdbc.Driver ) 甚至 new oracle.jdbc.Driver() 在你的代码中,看看会发生什么。
DriverManager.getDrivers()
Class.forName("oracle.jdbc.Driver
new oracle.jdbc.Driver()
您可能还想检查Sybase驱动程序的版本,以及是否有更新版本不执行此检查,尽管这可能只会导致错误发生在代码中的其他位置。