Oracle JDBC间歇性连接问题

时间:2010-02-24 15:38:58

标签: java oracle jdbc

我遇到了一个非常奇怪的问题 这是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(); }
    }
}

14 个答案:

答案 0 :(得分:90)

在某些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服务器端增加套接字超时也可以是一种解决方案,但在尝试此操作之前,应从服务器的角度评估副作用。

答案 1 :(得分:17)

我遇到了完全相同的问题。使用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 exception:   连接重置“)。

     

问题是双重的

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

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

  4.         

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

         

    原因尚未确切地确定原因。它可能   要么是硬件问题,要么是出于某种原因   该软件无法从dev / random

    读取      

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

         

    -Djava.security.egd =文件是:/ dev /../开发/ urandom的

         

    我们在java.security文件中进行了此更改,但它已被删除   错误。

解决了我的问题。

答案 2 :(得分:6)

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

由于间歇性发生,JDBC驱动程序中的错误可能会被排除在外或更少。留下剩下的可能原因。我建议首先查看数据库服务器的日志。

答案 3 :(得分:2)

很难说,但如果我要检查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文件。

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

答案 4 :(得分:2)

导致我出现此问题的其他因素是 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

答案 5 :(得分:1)

我发现这个链接与64位系统,驱动程序jdbc 11g和连接重置相同的问题: http://forums.oracle.com/forums/thread.jspa?messageID=3793101

答案 6 :(得分:1)

只是为了澄清 - 至少从我们在我们身边找到的东西来说明! 在JDK发行版中设置Linux随机化程序是一个问题 - 我们在Java6中发现它,不确定Java7。 随机化器的linux语法是file:/// dev / urandom,但文件中的条目(可能是从Windows保留/复制)作为文件:/ dev / urandom。 那么Java可能会回落到默认值,恰好是/ dev / random。这对无头机器无效!

答案 7 :(得分:1)

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

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验证程序。如果是这种情况,则需要再次检查配置。

答案 8 :(得分:0)

请注意,使用/ dev / urandom的建议解决方案对我来说第一次起作用,但在此之后总是不起作用。

我公司的DBA切换了'SQL * net banners',无论是否有上述内容,我都会永久修复它。

我不知道'SQL * net banners'是什么,但我希望在这里提供这些信息,如果你有一个DBA,他(你)会知道该怎么做。

答案 9 :(得分:0)

禁用SQL Net Banners保存了我们

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

Java不会出现 -Djava.security.egd = file:/ dev / urandom

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

答案 12 :(得分:0)

从詹金斯执行liquibase时,我遇到了同样的问题。有时,此错误被抛出到输出,而liquibase更改日志根本没有执行。

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

答案 13 :(得分:-1)

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

run -> services.msc 

并留意那些服务