Oracle JDBC 间歇性连接问题

2022-08-31 16:05:15

我遇到了一个非常奇怪的问题 这是JDBC连接到Oracle数据库的非常简单的使用

OS: Ubuntu
Java Version:  1.5.0_16-b02
               1.6.0_17-b04
Database: Oracle 11g Release 11.1.0.6.0

当我使用jar文件时,它每次都会连接到数据库当我使用jar文件时,它会连接一些时间,而其他时候它会抛出错误(如下所示)如果我重新编译Java 6并使用,我会得到与OJDBC14.jarOJDBC5.jarOJDBC6.jarOJDBC5.jar

我需要 JODB5 中的特定功能.jar这些功能在 OJDBC14 中不可用.jar

任何想法

错误

> Connecting to oracle
    java.sql.SQLException: Io exception: Connection reset
    at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:74)
    at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:110)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:171)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:227)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:494)
    at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:411)
    at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:490)
    at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:202)
    at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:33)
    at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:474)
    at java.sql.DriverManager.getConnection(DriverManager.java:525)
    at java.sql.DriverManager.getConnection(DriverManager.java:171)
    at TestConnect.main(TestConnect.java:13)

法典

以下是我正在使用的代码

import java.io.*;
import java.sql.*;
public class TestConnect {
    public static void main(String[] args) {
        try {
            System.out.println("Connecting to oracle"); 
            Connection con=null;
            Class.forName("oracle.jdbc.driver.OracleDriver");
            con=DriverManager.getConnection(
               "jdbc:oracle:thin:@172.16.48.100:1535:sample",
               "JOHN",
               "90009000");
            System.out.println("Connected to oracle"); 
            con.close();
            System.out.println("Goodbye");
        } catch(Exception e) { e.printStackTrace(); }
    }
}

答案 1

在一些OTN论坛(https://kr.forums.oracle.com/forums/thread.jspa?messageID=3699989)中提供了解决此问题的方法。但是,问题的根本原因没有得到解释。以下是我试图解释问题的根本原因。

Oracle JDBC 驱动程序以安全的方式与 Oracle 服务器进行通信。驱动程序使用 java.security.SecureRandom 类来收集用于保护通信的熵。此类依赖于本机平台支持来收集熵。

是由操作系统或应用程序收集/生成的随机性,用于加密或其他需要随机数据的用途。这种随机性通常从硬件源收集,无论是从硬件噪声、音频数据、鼠标移动还是从专门提供的随机性生成器中收集。内核收集熵并将其存储为熵池,并通过特殊文件 /dev/random 和 /dev/urandom 使随机字符数据可供操作系统进程或应用程序使用。

/dev/random 读取会耗尽熵池中请求的位数/字节数,从而提供加密操作中通常需要的高度随机性。如果熵池完全耗尽并且没有足够的熵可用,则对 /dev/random 块执行读取操作,直到收集到其他熵。因此,从 /dev/random 读取的应用程序可能会阻塞一段时间的随机时间段。

与上述相反,从 /dev/urandom 读取不会阻塞。从 /dev/urandom 读取也会耗尽熵池,但是当缺少足够的熵时,它不会阻塞,而是重用部分读取的随机数据中的位。据说这容易受到密码分析攻击。这是一种神学上的可能性,因此不鼓励从 /dev/urandom 读取以在加密操作中收集随机性。

默认情况下,java.security.SecureRandom 类从 /dev/random 文件中读取,因此有时会随机阻塞一段时间。现在,如果读取操作在所需的时间内未返回,则 Oracle 服务器会使客户端(在本例中为 jdbc 驱动程序)超时,并通过从其末端关闭套接字来断开通信。客户端在从阻塞调用返回后尝试恢复通信时遇到 IO 异常。此问题可能会在任何平台上随机发生,特别是从硬件噪声中收集熵的平台。

正如 OTN 论坛中所建议的,这个问题的解决方案是覆盖 java.security.SecureRandom 类的默认行为,以使用来自 /dev/urandom 的非阻塞读取,而不是从 /dev/random 进行阻塞读取。这可以通过将以下系统属性 -Djava.security.egd=file:///dev/urandom 添加到 JVM 来完成。虽然这对于 JDBC 驱动程序等应用程序来说是一个很好的解决方案,但对于执行核心加密操作(如加密密钥生成)的应用程序,则不鼓励这样做。

其他解决方案可能是使用适用于平台的不同随机播种器实现,这些实现不依赖于硬件噪声来收集熵。这样,您可能仍然需要覆盖java.security.SecureRandom的默认行为。

增加Oracle服务器端的套接字超时也可能是一种解决方案,但在尝试此操作之前,应从服务器的角度评估副作用。


答案 2

我面临着完全相同的问题。使用Windows Vista,我无法重现问题,但在Ubuntu上,我不断重现“连接重置”错误。

我发现 http://forums.oracle.com/forums/thread.jspa?threadID=941911&tstart=0&messageID=3793101

根据该论坛上的一位用户的说法:

我向甲骨文开了一张票,这是他们告诉我的。

java.security.SecureRandom 是 sun 提供的标准 API。在此类提供的各种方法中,void nextBytes(byte[]) 就是其中之一。此方法用于生成随机字节。Oracle 11g JDBC 驱动程序使用此 API 在登录期间生成随机数。使用Linux的用户一直遇到SQLException(“Io exception: Connection reset”)。

问题是双重的

  1. 当调用 SecureRandom.nextBytes(byte[]) 时,JVM 会尝试列出 /tmp(或由 -Djava.io.tmpdir 设置的备用 tmp 目录)中的所有文件。如果文件数很大,则该方法需要很长时间才能响应,从而导致服务器超时

  2. void nextBytes(byte[]) 方法在 Linux 上使用 /dev/random,在一些缺少随机数生成硬件的机器上,操作速度减慢到使整个登录过程停止的程度。最终用户遇到 SQLException(“Io 异常:连接重置”)

如果底层操作系统是在故障硬件上运行的Linux,则升级到11g的用户可能会遇到此问题。

原因 尚未确切确定其原因。这可能是硬件问题,也可能是由于某种原因软件无法从dev/random读取的事实。

解决方案 更改应用程序的设置,以便将下一个参数添加到 java 命令中:

-Djava.security.egd=file:/dev/../dev/urandom

我们在java.security文件中进行了此更改,并且它已经摆脱了错误。

这解决了我的问题。


推荐