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
Когда я использую файл JAROJDBC14.jar
он подключается к базе данных каждый раз, когда я использую файл JAROJDBC5.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(); }
}
}
13 ответов
Существует решение для этой проблемы на некоторых форумах OTN ( https://kr.forums.oracle.com/forums/thread.jspa?messageID=3699989). Но первопричина проблемы не объясняется. Ниже приведена моя попытка объяснить причину проблемы.
Драйверы JDBC Oracle взаимодействуют с сервером 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) и прекращает связь, закрывая сокет с его конца. Когда клиент пытается возобновить связь после возврата из блокирующего вызова, клиент обнаруживает исключение ввода-вывода. Эта проблема может возникать случайным образом на любой платформе, особенно, когда энтропия собирается из аппаратных помех.
Как предлагается на форуме OTN, решение этой проблемы состоит в том, чтобы переопределить поведение по умолчанию класса java.security.SecureRandom, чтобы использовать неблокирующее чтение из / dev / urandom вместо блокирующего чтения из / dev / random. Это можно сделать, добавив следующее системное свойство -Djava.security.egd=file:///dev/urandom в JVM. Хотя это хорошее решение для приложений, таких как драйверы JDBC, оно не рекомендуется для приложений, которые выполняют основные криптографические операции, такие как генерация криптографических ключей.
Другие решения могут заключаться в использовании различных реализаций случайных сеялок, доступных для платформы, которые не полагаются на аппаратные шумы для сбора энтропии. При этом вам все равно может потребоваться переопределить стандартное поведение java.security.SecureRandom.
Увеличение времени ожидания сокета на стороне сервера Oracle также может быть решением, но побочные эффекты должны быть оценены с точки зрения сервера, прежде чем пытаться это сделать.
Я столкнулся с точно такой же проблемой. В Windows Vista я не мог воспроизвести проблему, но в Ubuntu я постоянно воспроизводил ошибку "сброса соединения".
Я нашел http://forums.oracle.com/forums/thread.jspa?threadID=941911&tstart=0&messageID=3793101
По словам пользователя на этом форуме:
Я открыл билет с Oracle, и это то, что они сказали мне.
java.security.SecureRandom - это стандартный API, предоставляемый Sun. Среди различных методов, предлагаемых этим классом, void nextBytes(byte[]) - один. Этот метод используется для генерации случайных байтов. Драйверы Oracle 11g JDBC используют этот API для генерации случайного числа во время входа в систему. Пользователи, использующие Linux, сталкиваются с SQLException("Io исключения: сброс соединения").
Проблема в два раза
JVM пытается вывести список всех файлов в /tmp (или в альтернативном каталоге tmp, установленном -Djava.io.tmpdir), когда вызывается SecureRandom.nextBytes(byte[]). Если количество файлов велико, метод требует много времени для ответа и, следовательно, приводит к превышению времени ожидания сервера
Метод void nextBytes(byte[]) использует /dev/random в Linux, а на некоторых машинах, где отсутствует аппаратное обеспечение, генерирующее случайные числа, операция замедляется до такой степени, что весь процесс входа в систему останавливается. В конечном итоге пользователь сталкивается с SQLException("Io исключения: сброс соединения")
Пользователи, обновляющиеся до 11g, могут столкнуться с этой проблемой, если основной операционной системой является Linux, работающая на неисправном оборудовании.
Причина Причина этого еще точно не установлена. Это может быть проблема в вашем оборудовании или тот факт, что по какой-то причине программа не может читать из dev / random
Решение Измените настройку для своего приложения, добавив следующий параметр в команду java:
-Djava.security.egd = файл: / DEV /../ DEV /urandom
Мы внесли это изменение в наш файл java.security, и он избавился от ошибки.
который решил мою проблему.
Сообщение об ошибке "сброс соединения" обычно означает, что другая сторона прервала соединение во время попытки создать соединение (квитирование). Это имеет много возможных причин. Ошибка в драйвере JDBC, время ожидания на стороне БД, перезапуск базы данных, из-за нехватки доступных соединений в БД, плохое качество сети, плохой virusscanner/firewall/proxy и т. Д.
Поскольку это происходит периодически, ошибка в драйвере JDBC может быть в меньшей или меньшей степени исключена. Оставленные позади оставшиеся возможные причины. Предлагаю начать с просмотра логов сервера БД.
Трудно сказать, но если бы я проверил актуальную версию драйвера JDBC. Убедитесь, что это 11.1.0.6.
Oracle не включает версию базы данных в имя файла. Таким образом, драйвер для 11.2 - это то же имя, что и драйвер для 11.1 - ojdbc5.jar. Я бы распаковал файл jar драйвера и нашел бы файл MANIFEST.MF, он будет содержать некоторую информацию о версии. Убедитесь, что версия драйвера JDBC совпадает с версией вашей базы данных. Я подозреваю, что это может быть проблема с версией, поскольку на странице загрузки Oracle 11.1.0.6 нет файла jar с именем ojdbc14.jar.
Если версия совпадает - у меня нет идей:)
Другая причина, которая вызывала у меня эту проблему, заключалась в неправильных настройках 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
Согласно ошибке https://bugs.openjdk.java.net/browse/JDK-6202721
Java не будет обрабатывать -Djava.security.egd=file:/dev/urandom
Это должно быть -Djava.security.egd=file:/dev/./urandom
Я нашел эту ссылку для той же проблемы с 64-битной системой, драйвером jdbc 11g и сбросом соединения: http://forums.oracle.com/forums/thread.jspa?messageID=3793101
Просто чтобы уточнить - хотя бы из того, что мы нашли на нашей стороне! Это проблема с настройкой рандомизатора для Linux в дистрибутиве JDK - и мы нашли его в Java6, не уверенный в Java7. Синтаксис для linux для рандомизатора: file:/// dev / urandom, но запись в файле (вероятно, оставлена / скопирована из Windows) как file:/ dev / urandom. Тогда Java, вероятно, вернется к значению по умолчанию, которое будет / dev / random. И который не работает на безголовой машине!!!
Коренная причина этой проблемы связана с версиями аутентификации пользователя. Для каждого пользователя базы данных в базе данных хранится несколько верификаторов паролей. Обычно, когда вы обновляете базу данных, в список добавляется новый верификатор паролей, более сильный. Следующий запрос показывает версии верификатора пароля, доступные для каждого пользователя. Например:
SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT';
PASSWORD_VERSIONS
-----------------
11G 12C
При обновлении до более нового драйвера вы можете использовать более новую версию верификатора, поскольку драйвер и сервер согласовывают максимально возможный верификатор, который будет использоваться. Эта более новая версия верификатора будет более безопасной и будет включать генерацию больших случайных чисел или использование более сложных хеш-функций, которые могут объяснить, почему вы видите проблемы при установлении соединений JDBC. Как уже упоминалось в других ответах, использующих /dev/urandom
обычно решает эти проблемы. Вы также можете отказаться от проверки вашего пароля и заставить более новый драйвер использовать тот же самый старый верификатор пароля, который использовался вашим предыдущим драйвером. Например, если вы хотите использовать верификатор пароля 10G (только для целей тестирования), сначала необходимо убедиться, что он доступен для вашего пользователя. Задавать SQLNET.ALLOWED_LOGON_VERSION_SERVER=8
в sqlnet.ora на сервере. Затем:
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 использовать верификатор 10G, установив это свойство JDBC oracle.jdbc.thinLogonCapability="o3"
, Если вы столкнетесь с ошибкой "ORA-28040: No matching authentication protocol"
тогда это означает, что ваш сервер не позволяет использовать верификатор 10G. Если это так, то вам нужно снова проверить свою конфигурацию.
-Djava.security.egd=file:/dev/./urandom должен быть правильным! not -Djava.security.egd=file:/dev/../dev/urandom или -Djava.security.egd=file:///dev/urandom
Обратите внимание, что предложенное решение использования /dev/urandom сработало впервые для меня, но не сработало всегда после этого.
Администратор базы данных в моей фирме перешел на "баннеры SQL* net", и это навсегда исправило это для меня, как и прежде, без него.
Я не знаю, что такое "баннеры SQL* net", но надеюсь разместить эту информацию здесь, чтобы, если у вас есть (есть) администратор БД, он (вы) знал бы, что делать.
Я столкнулся с той же проблемой, когда ликвибаза была запущена из jenkins. Время от времени эта ошибка выдавалась на выходе, и журналы изменений ликвибазы не выполнялись вообще.
Предоставленное решение: в проекте jenkin's maven jdk был обновлен с jdk8-131 до любой более новой версии (например, java8-162).
OracleXETNSListener - эта служба должна быть запущена, если она была отключена.
run -> services.msc
и обратите внимание на эти услуги