web-dev-qa-db-fra.com

Problème de connexion intermittente Oracle JDBC

Je rencontre un problème très étrange Il s’agit d’une utilisation très simple de la connexion JDBC à une base de données Oracle

OS: Ubuntu
Java Version:  1.5.0_16-b02
               1.6.0_17-b04
Database: Oracle 11g Release 11.1.0.6.0

Quand je me sers du fichier jar OJDBC14.jar il se connecte à la base de données à chaque fois que je me sers du fichier jar OJDBC5.jar il se connecte quelques fois et jette une erreur (voir ci-dessous). Si je recompile avec Java 6 et utilise OJDBC6.jar _ J’obtiens les mêmes résultats que OJDBC5.jar

J'ai besoin de fonctionnalités spécifiques dans JODB5.jar qui ne sont pas disponibles dans OJDBC14.jar

Des idées

Erreur

> 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

Ci-dessous le code que j'utilise

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

Une solution à ce problème est fournie dans certains forums OTN ( https://kr.forums.Oracle.com/forums/thread.jspa?messageID=3699989 ). Mais, la cause du problème n’est pas expliquée. Voici ma tentative d’expliquer la cause première du problème.

Les pilotes JDBC Oracle communiquent avec le serveur Oracle de manière sécurisée. Les pilotes utilisent la classe Java.security.SecureRandom pour recueillir l'entropie afin de sécuriser la communication. Cette classe repose sur le support de la plateforme native pour la collecte de l'entropie.

L'entropie est le caractère aléatoire collecté/généré par un système d'exploitation ou une application pour une utilisation en cryptographie ou pour d'autres utilisations nécessitant des données aléatoires. Ce caractère aléatoire est souvent collecté à partir de sources matérielles, soit des bruits matériels, des données audio, des mouvements de souris ou des générateurs d'aléa spécialement fournis. Le noyau rassemble l'entropie et le stocke dans un pool d'entropie. Il met les données de caractères aléatoires à la disposition des processus ou des applications du système d'exploitation via les fichiers spéciaux / dev/random et / dev/urandom.

Lire à partir de / dev/random draine le pool d'entropie avec le nombre de bits/octets demandé, offrant souvent un degré élevé d'aléatoire. souhaité dans les opérations cryptographiques. Si le pool d'entropie est complètement vidé et qu'aucune entropie suffisante n'est disponible, l'opération de lecture sur / dev/random bloque jusqu'à ce qu'une entropie supplémentaire soit collectée. De ce fait, les applications lues à partir de / dev/random peuvent se bloquer pendant une période aléatoire.

Contrairement à ce qui précède, la lecture du / dev/urandom ne bloque pas. Lire à partir de / dev/urandom draine également le pool d'entropie mais s'il manque d'entropie suffisante, il ne bloque pas réutilise les bits des données aléatoires partiellement lues. On dit que cela est susceptible d'attaques cryptanalytiques. Ceci est une possibilité théorique et il est donc déconseillé de lire / dev/urandom pour rassembler le hasard dans les opérations cryptographiques.

La classe Java.security.SecureRandom, par défaut, lit le fichier / dev/random et bloque donc parfois pour une période aléatoire. Désormais, si l'opération de lecture ne retourne pas pendant le temps requis, le serveur Oracle expire le client (les pilotes jdbc, dans ce cas) et interrompt la communication en fermant le socket de son extrémité. Lorsque le client tente de reprendre la communication après son retour de l'appel bloquant, il rencontre l'exception = IO. Ce problème peut se produire de manière aléatoire sur toute plate-forme, en particulier lorsque l'entropie est collectée à partir de bruits matériels.

Comme suggéré sur le forum OTN, la solution à ce problème consiste à remplacer le comportement par défaut de la classe Java.security.SecureRandom afin d'utiliser la lecture non bloquante de / dev/urandom = au lieu du blocage lu à partir de / dev/random. Cela peut être fait en ajoutant la propriété système suivante -Djava.security.egd = fichier: /// dev/urandom à la JVM. Bien que ce soit une bonne solution pour les applications telles que les pilotes JDBC, elle est déconseillée pour les applications qui effectuent des opérations cryptographiques essentielles telles que la génération de clés cryptographiques.

D'autres solutions pourraient consister à utiliser différentes implémentations de seeder aléatoire disponibles pour la plate-forme qui ne reposent pas sur des bruits matériels pour la collecte d'entropie. Avec cela, vous pouvez toujours avoir besoin de remplacer le comportement par défaut de Java.security.SecureRandom.

Augmenter le délai d'expiration du socket côté serveur Oracle peut également être une solution, mais les effets secondaires doivent être évalués du point de vue du serveur avant toute tentative.

91
Drona

Je faisais face exactement au même problème. Avec Windows Vista, je ne pouvais pas reproduire le problème, mais sous Ubuntu, je reproduisais constamment l'erreur de "réinitialisation de la connexion".

J'ai trouvé http://forums.Oracle.com/forums/thread.jspa?threadID=941911&tstart=0&messageID=3793101

Selon un utilisateur de ce forum:

J'ai ouvert un ticket avec Oracle et c'est ce qu'ils m'ont dit.

Java.security.SecureRandom est une API standard fournie par Sun. Parmi les différentes méthodes offertes par cette classe, void nextBytes (byte []) en est une. Cette méthode est utilisée pour générer des octets aléatoires. Les pilotes JDBC Oracle 11g utilisent cette API pour générer un nombre aléatoire lors de la connexion. Les utilisateurs de Linux ont rencontré SQLException ("exception Io: réinitialisation de la connexion").

Le problème est double

  1. La machine virtuelle Java tente de répertorier tous les fichiers du répertoire/tmp (ou le répertoire de remplacement tmp défini par -Djava.io.tmpdir) lorsque SecureRandom.nextBytes (byte []) est appelé. Si le nombre de fichiers est important, la méthode prend beaucoup de temps pour répondre et entraîne par conséquent un dépassement du délai d'attente du serveur.

  2. La méthode void nextBytes (byte []) utilise/dev/random sous Linux et sur certaines machines dépourvues du matériel générant un nombre aléatoire, l'opération est ralentie au point d'arrêter tout le processus de connexion. En fin de compte l'utilisateur rencontre SQLException ("exception Io: réinitialisation de la connexion")

Les utilisateurs effectuant une mise à niveau vers la version 11g peuvent rencontrer ce problème si le système d'exploitation sous-jacent est Linux, qui s'exécute sur un matériel défectueux.

Cause La cause de ceci n'a pas encore été déterminée avec précision. Cela pourrait être un problème de votre matériel ou le fait que, pour une raison quelconque, le logiciel ne puisse pas lire à partir de dev/random

Solution Modifiez la configuration de votre application afin d’ajouter le paramètre suivant à la commande Java:

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

Nous avons apporté cette modification à notre fichier Java.security et il s’est débarrassé de l’erreur.

qui a résolu mon problème.

17
Camilla

Un message d'erreur "connexion réinitialisée" signifie généralement que l'autre côté a interrompu la connexion lors de la tentative de création d'une connexion (l'établissement de liaison). Cela a beaucoup de causes possibles. Un bogue dans le pilote JDBC, une temporisation du côté de la base de données, un redémarrage de la base de données, la base de données étant à court de connexions disponibles, une qualité de réseau médiocre, un mauvais virusscanner/pare-feu/proxy, etc.

Comme cela arrive de temps en temps, un bogue dans le pilote JDBC peut être moins ou plus exclu. Laissé derrière les causes possibles restantes. Je suggère de commencer par regarder dans les journaux du serveur de base de données.

6
BalusC

C'est difficile à dire, mais si je vérifiais la version actuelle du pilote JDBC. Assurez-vous que c'est 11.1.0.6.

Oracle n'inclut pas la version de la base de données dans le nom du fichier. Donc, le pilote pour 11.2 est exactement le même nom que le pilote pour 11.1 - ojdbc5.jar. Je voudrais extraire le fichier jar du pilote et trouver le fichier MANIFEST.MF, qui contiendra des informations de version. Assurez-vous que la version du pilote JDBC correspond à la version de votre base de données. Je suppose que cela pourrait être un problème de version, car il n’existe pas de fichier jar nommé ojdbc14.jar sur la page Oracle 11.1.0.6 à télécharger .

Si la version correspond - je suis à court d'idées :)

3
Steve K

Une autre chose qui me causait ce problème était d'avoir les mauvais NOM D'HÔTE . Ma tentative de connexion a été pendue à:

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

Assurez-vous donc d'avoir une entrée pour votre nom d'hôte dans /etc/hosts/.

Si vous émettez une commande hostname comme ceci:

$ hostname
my.server.com

Vous avez besoin d'une ligne dans votre /etc/hosts:

127.0.0.1 my my.server.com
2
Pablo Santa Cruz

J'ai trouvé ce lien pour le même problème avec le système 64 bits, le pilote jdbc 11g et la réinitialisation de la connexion: http://forums.Oracle.com/forums/thread.jspa?messageID=3793101

1
am yourks

La cause première de ce problème est liée aux versions d'authentification de l'utilisateur. Pour chaque utilisateur de base de données, plusieurs vérificateurs de mot de passe sont conservés dans la base de données. Généralement, lorsque vous mettez à niveau votre base de données, un nouveau vérificateur de mot de passe sera ajouté à la liste, un plus puissant. La requête suivante affiche les versions du vérificateur de mot de passe disponibles pour chaque utilisateur. Par exemple:

SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT';

PASSWORD_VERSIONS
-----------------
11G 12C

Lors de la mise à niveau vers un pilote plus récent, vous pouvez utiliser une version plus récente du vérificateur, car le pilote et le serveur négocient le vérificateur le plus puissant possible. Cette version plus récente du vérificateur sera plus sécurisée et impliquera la génération de nombres aléatoires plus importants ou l'utilisation de fonctions de hachage plus complexes pouvant expliquer pourquoi vous rencontrez des problèmes lors de l'établissement de connexions JDBC. Comme mentionné par d'autres réponses en utilisant /dev/urandom résout normalement ces problèmes. Vous pouvez également décider de déclasser votre vérificateur de mot de passe et de faire en sorte que le dernier pilote utilise le même vérificateur de mot de passe plus ancien que celui utilisé par votre précédent pilote. Par exemple, si vous souhaitez utiliser le vérificateur de mot de passe 10G (à des fins de test uniquement), vous devez d'abord vous assurer qu'il est disponible pour votre utilisateur. Ensemble SQLNET.ALLOWED_LOGON_VERSION_SERVER=8 dans sqlnet.ora sur le serveur. Ensuite:

SQL> alter user scott identified by "tiger";

User altered.

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

Ensuite, vous pouvez forcer le pilote léger JDBC à utiliser le vérificateur 10G en définissant cette propriété JDBC Oracle.jdbc.thinLogonCapability="o3". Si vous rencontrez l'erreur "ORA-28040: No matching authentication protocol" _ cela signifie que votre serveur n'autorise pas l'utilisation du vérificateur 10G. Si tel est le cas, vous devez vérifier votre configuration à nouveau.

1
Jean de Lavarene

Juste pour clarifier - du moins d'après ce que nous avons trouvé de notre côté! C'est un problème avec la configuration du randomizer pour Linux dans la distribution JDK - et nous l'avons trouvé dans Java6, pas sûr de Java7. La syntaxe pour linux pour le randomiseur est file: /// dev/urandom, mais l'entrée dans le fichier est (probablement laissée/copiée à partir de Windows) sous la forme fichier:/dev/urandom. Donc Java revient probablement sur la valeur par défaut, qui est/dev/random. Et qui ne fonctionne pas sur une machine sans tête !!!

1
user1824684

Selon le bogue https://bugs.openjdk.Java.net/browse/JDK-6202721

Java ne consdera pas - Djava.security.egd = fichier:/dev/urandom

Cela devrait être - Djava.security.egd = fichier:/dev /./ urandom

0
Javadroider

La désactivation des bannières SQL Net nous a sauvé.

0
user1475669

-Djava.security.egd = fichier:/dev /./ urandom devrait avoir raison! pas -Djava.security.egd = fichier:/dev /../ dev/urandom ou -Djava.security.egd = fichier: /// dev/urandom

0
user5155790

Notez que la solution suggérée consistant à utiliser/dev/urandom a fonctionné la première fois pour moi, mais n’a pas toujours fonctionné par la suite.

Dans mon entreprise, les administrateurs de bases de données ont remplacé les 'bannières SQL * net' et les ont résolus de manière permanente, avec ou sans ce qui précède.

Je ne sais pas ce que sont les 'bannières SQL * net', mais j'espère en mettant ces informations ici que si vous avez (êtes) un administrateur de base de données, il saura quoi faire.

0
Vishal Saxena