Java Oracle JDBC 间歇性连接问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2327220/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 06:11:47  来源:igfitidea点击:

Oracle JDBC intermittent Connection Issue

javaoraclejdbc

提问by Lipska

I am experiencing a very strange problem This is a very simple use of JDBC connecting to an Oracle database

我遇到了一个很奇怪的问题这是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

When I make use of the jar file OJDBC14.jarit connects to the database everytime When I make use of the jar file OJDBC5.jarit connects some times and other times it throws an error ( shown below) If I recompile with Java 6 and use OJDBC6.jarI get the same results as OJDBC5.jar

当我使用 jar 文件时, OJDBC14.jar它每次都连接到数据库当我使用 jar 文件时, OJDBC5.jar它有时会连接,有时会抛出错误(如下所示)如果我使用 Java 6 重新编译并使用, OJDBC6.jar我会得到相同的结果作为OJDBC5.jar

I need specific features in JODB5.jar that are not available in OJDBC14.jar

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

Any ideas

有任何想法吗

Error

错误

> 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)

Code

代码

Below is the code I am using

下面是我正在使用的代码

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(); }
    }
}

回答by Steve K

It's hard to say, but if I would check the actual version of the JDBC driver. Make sure it's 11.1.0.6.

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

Oracle doesn't include the database version in the filename. So the driver for 11.2 is the exact same name as the driver for 11.1 - ojdbc5.jar. I would extract the driver jar file, and find the MANIFEST.MF file, this will contain some version information. Make sure the version of the JDBC driver matches the version of your database. I suspect it may be a version issue, since there isn't a jar file named ojdbc14.jar on Oracle's 11.1.0.6 downloadpage.

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

If the version matches - I'm out of ideas :)

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

回答by BalusC

A "connection reset" error message generally means that the other side has aborted the connection during the attempt to create a connection (the handshake). This has a lot of possible causes. A bug in the JDBC driver, a timeout at the DB side, a restart of the database, the DB being run out of available connections, poor network quality, bad virusscanner/firewall/proxy, etc.

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

As it happens intermittely, a bug in the JDBC driver can be less or more excluded. Left behind the remaining possible causes. I suggest to start with looking in the logs of the DB server.

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

回答by Camilla

I was facing exactly the same problem. With Windows Vista I could not reproduce the problem but on Ubuntu I reproduced the 'connection reset'-Error constantly.

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

I found http://forums.oracle.com/forums/thread.jspa?threadID=941911&tstart=0&messageID=3793101

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

According to a user on that forum:

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

I opened a ticket with Oracle and this is what they told me.

java.security.SecureRandom is a standard API provided by sun. Among various methods offered by this class void nextBytes(byte[]) is one. This method is used for generating random bytes. Oracle 11g JDBC drivers use this API to generate random number during login. Users using Linux have been encountering SQLException("Io exception: Connection reset").

The problem is two fold

  1. The JVM tries to list all the files in the /tmp (or alternate tmp directory set by -Djava.io.tmpdir) when SecureRandom.nextBytes(byte[]) is invoked. If the number of files is large the method takes a long time to respond and hence cause the server to timeout

  2. The method void nextBytes(byte[]) uses /dev/random on Linux and on some machines which lack the random number generating hardware the operation slows down to the extent of bringing the whole login process to a halt. Ultimately the the user encounters SQLException("Io exception: Connection reset")

Users upgrading to 11g can encounter this issue if the underlying OS is Linux which is running on a faulty hardware.

Cause The cause of this has not yet been determined exactly. It could either be a problem in your hardware or the fact that for some reason the software cannot read from dev/random

Solution Change the setup for your application, so you add the next parameter to the java command:

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

We made this change in our java.security file and it has gotten rid of the error.

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

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 exception: Connection reset")

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

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

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

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

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

which solved my problem.

这解决了我的问题。

回答by Drona

There is a solution provided to this problem in some of the OTN forums (https://kr.forums.oracle.com/forums/thread.jspa?messageID=3699989). But, the root cause of the problem is not explained. Following is my attempt to explain the root cause of the problem.

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

The Oracle JDBC drivers communicate with the Oracle server in a secure way. The drivers use the java.security.SecureRandomclass to gather entropy for securing the communication. This class relies on the native platform support for gathering the entropy.

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

Entropyis the randomness collected/generated by an operating system or application for use in cryptography or other uses that require random data. This randomness is often collected from hardware sources, either from the hardware noises, audio data, mouse movements or specially provided randomness generators. The kernel gathers the entropy and stores it is an entropy pool and makes the random character data available to the operating system processes or applications through the special files /dev/randomand /dev/urandom.

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

Reading from /dev/randomdrains the entropy pool with requested amount of bits/bytes, providing a high degree of randomness often desired in cryptographic operations. In case, if the entropy pool is completely drained and sufficient entropy is not available, the read operation on /dev/randomblocks until additional entropy is gathered. Due to this, applications reading from /dev/randommay block for some random period of time.

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

In contrast to the above, reading from the /dev/urandomdoes not block. Reading from /dev/urandom, too, drains the entropy pool but when short of sufficient entropy, it does not block but reuses the bits from the partially read random data. This is said to be susceptible to cryptanalytical attacks. This is a theorotical possibility and hence it is discouraged to read from /dev/urandomto gather randomness in cryptographic operations.

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

The java.security.SecureRandomclass, by default, reads from the /dev/randomfile and hence sometimes blocks for random period of time. Now, if the read operation does not return for a required amount of time, the Oracle server times out the client (the jdbc drivers, in this case) and drops the communication by closing the socket from its end. The client when tries to resume the communication after returning from the blocking call encounters the IO exception. This problem may occur randomly on any platform, especially, where the entropy is gathered from hardware noises.

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

As suggested in the OTN forum, the solution to this problem is to override the default behaviour of java.security.SecureRandomclass to use the non-blocking read from /dev/urandominstead of the blocking read from /dev/random. This can be done by adding the following system property -Djava.security.egd=file:///dev/urandomto the JVM. Though this is a good solution for the applications like the JDBC drivers, it is discouraged for applications that perform core cryptographic operations like crytographic key generation.

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

Other solutions could be to use different random seeder implementations available for the platform that do not rely on hardware noises for gathering entropy. With this, you may still require to override the default behaviour of java.security.SecureRandom.

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

Increasing the socket timeout on the Oracle server side can also be a solution but the side effects should be assessed from the server point of view before attempting this.

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

回答by Vishal Saxena

Note that the suggested solution of using /dev/urandom did work the first time for me but didn't work always after that.

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

DBA at my firm switched of 'SQL* net banners' and that fixed it permanently for me with or without the above.

我公司的 DBA 切换了“SQL* 网络横幅”,无论是否采用上述方法,都为我永久修复了它。

I don't know what 'SQL* net banners' are, but am hoping by putting this information here that if you have(are) a DBA he(you) would know what to do.

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

回答by Vishal Saxena

Disabling SQL Net Banners saved us.

禁用 SQL Net Banners 拯救了我们

回答by user1824684

Just to clarify - at least from what we found on our side! It is an issue with the setup of the randomizer for Linux in the JDK distribution - and we found it in Java6, not sure about Java7. The syntax for linux for the randomizer is file:///dev/urandom, but the entry in the file is (probably left/copied from Windows) as file:/dev/urandom. So then Java probably falls back on the default, which happens to be /dev/random. And which doesn't work on a headless machine!!!

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

回答by Pablo Santa Cruz

Other thing that was causing me this problem was having the HOSTNAMEsettings wrong. My connection attempt was hanged at:

导致我出现此问题的另一件事是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.run(SeedGenerator.java:176)
        at sun.security.provider.SeedGenerator.run(SeedGenerator.java:162)
        at java.security.AccessController.doPrivileged(Native Method)

So make sure you have an entry for your hostname in /etc/hosts/.

因此,请确保您的主机名在/etc/hosts/.

If you issue a hostnamecommand like this:

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

$ hostname
my.server.com

You need a line in your /etc/hosts:

你需要在你的一行/etc/hosts

127.0.0.1 my my.server.com

回答by seetaram

OracleXETNSListener - this service has to be started if it was disabled.

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

run -> services.msc 

and look out for that services

并留意那些服务

回答by user5155790

-Djava.security.egd=file:/dev/./urandom should be right! not -Djava.security.egd=file:/dev/../dev/urandom or -Djava.security.egd=file:///dev/urandom

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