【问题标题】:Oracle JDBC: set timeout for "Unknown host specified"Oracle JDBC:为“指定的未知主机”设置超时
【发布时间】:2020-11-03 14:34:42
【问题描述】:

这个和类似的问题被问了很多次,但没有一个推荐的设置对我有用。

如果数据库主机不可用或 Oracle DB 仍未启动和运行,我需要为这种情况配置超时。

我需要在 Docker 中检查 Oracle DB 服务器的状态,因此我在 bash 循环中执行 select 1 from dual,但 DriverManager.getConnection 在 20 秒后返回(除了提到的异常),这对我来说太多了。我想将此超时减少到 1 秒。

我知道有一个名为 TNSPING 的 Oracle 工具,用于检查 Oracle DB Server 状态,但不幸的是,这个工具不是官方 Oracle DB 映像的一部分,我不想在 Docker 中安装任何 Oracle 产品只是因为TNSPING。

这是我迄今为止尝试过的,但我使用的设置对此超时没有影响。 java.sql.SQLRecoverableException: IO Error: The Network Adapter could not establish the connection 异常在 20 秒后出现。而不是 1 秒。没关系我在java代码中使用1、1000或10000,超时总是20秒。

private Connection getConnection(String jdbcUrl) throws SQLException {
    String timeout = "100";
    Properties p = new Properties();
    p.put(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CONNECT_TIMEOUT, timeout);
    p.put(OracleConnection.CONNECTION_PROPERTY_THIN_READ_TIMEOUT, timeout);
    p.put(OracleConnection.CONNECTION_PROPERTY_THIN_JNDI_LDAP_CONNECT_TIMEOUT, timeout);
    p.put(OracleConnection.CONNECTION_PROPERTY_THIN_JNDI_LDAP_READ_TIMEOUT, timeout);
    p.put(OracleConnection.CONNECTION_PROPERTY_THIN_OUTBOUND_CONNECT_TIMEOUT, timeout);
    p.put(OracleConnection.CONNECTION_PROPERTY_DOWN_HOSTS_TIMEOUT, timeout);
    p.put("oracle.jdbc.ReadTimeout", timeout);
    p.put("oracle.net.CONNECT_TIMEOUT", timeout);

    p.put (OracleConnection.CONNECTION_PROPERTY_USER_NAME, user);
    p.put (OracleConnection.CONNECTION_PROPERTY_PASSWORD, password);

    System.setProperty("oracle.net.READ_TIMEOUT", timeout);
    System.setProperty("oracle.jdbc.ReadTimeout", timeout);
    System.setProperty("oracle.jdbc.javaNetNio", "true");

    DriverManager.setLoginTimeout(Integer.valueOf(timeout));
    Connection connection = DriverManager.getConnection(jdbcUrl, p);
    connection.setNetworkTimeout(Executors.newSingleThreadExecutor(), Integer.valueOf(timeout));

    return connection;
}

我不想在我的简单应用程序中添加连接池解决方案,只有纯 JDBC 对我来说就足够了。

我错过了什么?

-- 更新--

似乎问题是特定于环境的,可能与 Java 无关,但仍不确定。

如果我在我的机器和 Docker 中执行完全相同的命令,那么我会得到不同的执行时间:

命令:

$ time java -jar sql-runner-0.2.0-SNAPSHOT-with-dependencies.jar -j jdbc:oracle:thin:@//somehost:1521/somedb -U "doesnotmatter" -P "password" "select 1 from dual"

docker中的结果:

IO Error: Unknown host specified 

real    0m20.521s
user    0m0.764s
sys 0m0.097s

如果我在我的机器上执行它的结果:

IO Error: Unknown host specified 

real    0m0.501s
user    0m0.715s
sys 0m0.095s

完整的源代码可在here获取。

这种行为太奇怪了。

【问题讨论】:

  • 您使用哪个 JDBC 版本?尝试使用 tcpdump 进行检查,或者使用_g.jar 版本并打开跟踪。您是连接到独立数据库还是 RAC?
  • 我使用的 JDBC 驱动是ojdbc8, v12.2.0.1。我用于测试的 Oracle 数据库版本是官方的、未改动的 store/oracle/database-enterprise:12.2.0.1 Docker 镜像。您可以从此处提取并检查代码:github.com/zappee/sql-runner 如果您能提供帮助,您可以为该项目做出贡献;)
  • 你有没有尝试过这样的事情:stackoverflow.com/a/10705424
  • 不幸的是,sun.net.client.* 属性没有帮助。更新的源代码可在此处获得:github.com/zappee/sql-runner/blob/set-timeout/src/main/java/com/… 也许它来自完全不同的级别,而不是来自 JDBC 驱动程序?也许这是一个特定于环境的问题......

标签: java database oracle docker jdbc


【解决方案1】:

这对您不起作用可能有多种原因:

  • 取决于 JDBC 驱动程序版本超时可以是毫秒或秒
  • 您设置的某些选项会被您的驱动程序版本忽略
  • DNS 可能存在各种问题,例如 Oracle SCAN 侦听器将您重定向到 RAC 集群节点。而且您的客户端无法解析该主机名。

您有以下选项来诊断您的问题:

追踪:

strace -f -e trace=network -o strace.log java -jar sql-runner-0.2.0-SNAPSHOT-with-dependencies.jar -j jdbc:oracle:thin:@//somehost:1521/somedb -U "doesnotmatter" -P "password" "select 1 from dual"

启用调试的 JDBC 驱动程序 (*_g.jar):

$ java -Doracle.jdbc.Trace=true \ 
-Djava.util.logging.config.file=Logging.properties \
-classpath "ojdbc8_g.jar:..." \
...

$ cat Logging.properties
.level=OFF

#.level=SEVERE
handlers=java.util.logging.FileHandler

#  example of a full pathname in Windows
java.util.logging.FileHandler.pattern=Networkpacket.log

# Predefined levels are: ALL, SEVERE, WARNING, INFO, CONFIG, FINE, FINER,
#                        FINEST, OFF

java.util.logging.FileHandler.limit = 500000000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.level =ALL
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
oracle.net.ns.level = ALL

## Following levels are commented to filter the network packet contents.

#oracle.jdbc.level=oFF
#oracle.jdbc.aq.level=OFF
#oracle.jdbc.driver.level=OFF
#oracle.jdbc.pool.level=OFF
#oracle.jdbc.rowset.level=OFF
#oracle.jdbc.xa.level=OFF
#oracle.sql.level=OFF

【讨论】:

  • 我对@9​​87654323@ 日志不熟悉,但我可以在 docker 中看到 DNS 请求响应不同。码头工人:1405 connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.11")}, 16) = 0。我还需要检查 Networkpacket.log。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多