【问题标题】:Oracle JDBC intermittent Connection IssueOracle JDBC 间歇性连接问题
【发布时间】:2011-01-20 14:20:30
【问题描述】:

我遇到了一个非常奇怪的问题 这是一个非常简单的使用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 文件时 OJDBC14.jar 每次都连接数据库 当我使用 jar 文件时 OJDBC5.jar 它有时会连接,有时会抛出错误(如下所示) 如果我用 Java 6 重新编译并使用 OJDBC6.jar我得到的结果和OJDBC5.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(); }
    }
}

【问题讨论】:

  • 我也有同样的问题,解决了吗?

标签: java oracle jdbc


【解决方案1】:

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

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

是由操作系统或应用程序收集/生成的随机性,用于密码学或其他需要随机数据的用途。这种随机性通常是从硬件来源收集的,无论是来自硬件噪声、音频数据、鼠标移动还是专门提供的随机性发生器。内核收集熵并将其存储为一个熵池,并通过特殊文件 /dev/random/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 阻塞读取。这可以通过向 JVM 添加以下系统属性 -Djava.security.egd=file:///dev/urandom 来完成。虽然这对于 JDBC 驱动程序等应用程序来说是一个很好的解决方案,但对于执行诸如加密密钥生成等核心加密操作的应用程序来说,这是不鼓励的。

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

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

【讨论】:

【解决方案2】:

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

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

根据该论坛上的用户:

我向 Oracle 开了一张票,这就是他们告诉我的。

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

问题有两个

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

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

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

原因 其原因尚未准确确定。它可能 要么是你的硬件有问题,要么是由于某种原因 该软件无法从 dev/random 读取

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

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

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

这解决了我的问题。

【讨论】:

    【解决方案3】:

    “连接重置”错误消息通常意味着对方在尝试创建连接(握手)期间中止了连接。这有很多可能的原因。 JDBC驱动的bug、DB端超时、数据库重启、DB用完可用连接、网络质量差、病毒扫描器/防火墙/代理坏等。

    由于它是间歇性发生的,因此可以或多或少地排除 JDBC 驱动程序中的错误。留下剩余的可能原因。我建议从查看数据库服务器的日志开始。

    【讨论】:

      【解决方案4】:

      很难说,但如果我会检查 JDBC 驱动程序的实际版本。确保它是 11.1.0.6。

      Oracle 在文件名中不包含数据库版本。因此 11.2 的驱动程序与 11.1 的驱动程序名称完全相同 - ojdbc5.jar。我将提取驱动程序 jar 文件,并找到 MANIFEST.MF 文件,这将包含一些版本信息。确保 JDBC 驱动程序的版本与您的数据库的版本相匹配。我怀疑这可能是版本问题,因为 Oracle 的 11.1.0.6 download 页面上没有名为 ojdbc14.jar 的 jar 文件。

      如果版本匹配 - 我没有想法 :)

      【讨论】:

        【解决方案5】:

        导致我出现此问题的其他原因是 HOSTNAME 设置错误。我的连接尝试挂在:

        "main" prio=10 tid=0x00007f7cc8009000 nid=0x2f3a runnable [0x00007f7cce69e000]
           java.lang.Thread.State: RUNNABLE
                at java.net.Inet4AddressImpl.getLocalHostName(Native Method)
                at java.net.InetAddress.getLocalHost(InetAddress.java:1444)
                at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:176)
                at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:162)
                at java.security.AccessController.doPrivileged(Native Method)
        

        所以请确保您在 /etc/hosts/ 中有一个主机名条目。

        如果您发出这样的hostname 命令:

        $ hostname
        my.server.com
        

        您需要在/etc/hosts 中添加一行:

        127.0.0.1 my my.server.com
        

        【讨论】:

          【解决方案6】:

          根据错误https://bugs.openjdk.java.net/browse/JDK-6202721

          Java 不会考虑 -Djava.security.egd=file:/dev/urandom

          应该是-Djava.security.egd=file:/dev/./urandom

          【讨论】:

            【解决方案7】:

            只是为了澄清 - 至少从我们发现的情况来看! 这是在 JDK 发行版中为 Linux 设置随机器的问题——我们在 Java6 中发现了它,不确定 Java7。 linux 的随机器语法是 file:///dev/urandom,但文件中的条目(可能是从 Windows 留下/复制的)为 file:/dev/urandom。 因此,Java 可能会退回到默认值,即 /dev/random。这在无头机器上不起作用!!!

            【讨论】:

              【解决方案8】:

              此问题的根本原因与用户身份验证版本有关。对于每个数据库用户,数据库中保存了多个密码验证器。通常,当您升级数据库时,会在列表中添加一个新的密码验证器,一个更强大的验证器。以下查询显示了可供每个用户使用的密码验证程序版本。例如:

              SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT';
              
              PASSWORD_VERSIONS
              -----------------
              11G 12C
              

              升级到较新的驱动程序时,您可以使用较新版本的验证程序,因为驱动程序和服务器会协商要使用的最强大的验证程序。这个新版本的验证器将更加安全,并且将涉及生成更大的随机数或使用更复杂的散列函数,这可以解释为什么您在建立 JDBC 连接时会看到问题。正如其他使用/dev/urandom 的回复所提到的,通常可以解决这些问题。您还可以决定降级您的密码验证器,并让较新的驱动程序使用与以前的驱动程序相同的旧密码验证器。例如,如果您想使用 10G 密码验证器(仅用于测试目的),首先您需要确保它对您的用户可用。 在服务器上的 sqlnet.ora 中设置SQLNET.ALLOWED_LOGON_VERSION_SERVER=8。那么:

              SQL> alter user scott identified by "tiger";
              
              User altered.
              
              SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT';
              PASSWORD_VERSIONS
              -----------------
              10G 11G 12C
              

              然后您可以通过设置此 JDBC 属性 oracle.jdbc.thinLogonCapability="o3" 来强制 JDBC 瘦驱动程序使用 10G 验证程序。如果您遇到错误"ORA-28040: No matching authentication protocol",则表示您的服务器不允许使用 10G 验证程序。如果是这种情况,那么您需要再次检查您的配置。

              【讨论】:

                【解决方案9】:

                请注意,使用 /dev/urandom 的建议解决方案对我来说第一次确实有效,但之后并不总是有效。

                我公司的 DBA 关闭了“SQL* 网络横幅”,无论是否使用上述内容,它都会为我永久修复。

                我不知道“SQL* 网络横幅”是什么,但我希望通过将这些信息放在这里,如果您拥有 DBA,他(您)会知道该怎么做。

                【讨论】:

                  【解决方案10】:

                  禁用 SQL 网络横幅拯救了我们

                  【讨论】:

                    【解决方案11】:

                    -Djava.security.egd=file:/dev/./urandom 应该是对的!不是 -Djava.security.egd=file:/dev/../dev/urandom 或 -Djava.security.egd=file:///dev/urandom

                    【讨论】:

                    • 如果你能添加一些解释,这是什么,以及为什么它是一个解决方案,那就太棒了。
                    • 在 Java Web 应用程序中是否可以将属性设置为 "System.setProperty("java.security.egd", "file:/dev/./urandom")" ?
                    【解决方案12】:

                    当从 jenkins 执行 liquibase 时,我遇到了同样的问题。偶尔会在输出中抛出此错误,并且根本没有执行 liquibase 更改日志。

                    提供的解决方案:在 jenkin 的 maven 项目中,jdk 从 jdk8-131 更新到任何较新的版本(例如 java8-162)。

                    【讨论】:

                      【解决方案13】:

                      OracleXETNSListener - 如果禁用此服务,则必须启动它。

                      run -> services.msc 
                      

                      并留意那些服务

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2014-07-16
                        • 1970-01-01
                        • 2023-02-26
                        相关资源
                        最近更新 更多