Je reçois une exception SQL ORA-01000. J'ai donc quelques questions à ce sujet.
- Le nombre maximal de curseurs ouverts est-il exactement lié au nombre de connexions JDBC, ou sont-ils également liés aux objets instruction et jeu de résultats que nous avons créés pour une seule connexion? (Nous utilisons un pool de connexions)
- Existe-t-il un moyen de configurer le nombre d'objets instruction / ensemble de résultats dans la base de données (comme les connexions)?
- Est-il conseillé d'utiliser un objet instruction / ensemble de résultats de variable d'instance au lieu d'une instruction locale de méthode / objet d'ensemble de résultats dans un environnement à thread unique?
L'exécution d'une instruction préparée dans une boucle provoque-t-elle ce problème? (Bien sûr, j'aurais pu utiliser sqlBatch) Remarque: pStmt est fermé une fois la boucle terminée.
{ //method try starts String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)"; pStmt = obj.getConnection().prepareStatement(sql); pStmt.setLong(1, subscriberID); for (String language : additionalLangs) { pStmt.setInt(2, Integer.parseInt(language)); pStmt.execute(); } } //method/try ends { //finally starts pStmt.close() } //finally ends
Que se passera-t-il si conn.createStatement () et conn.prepareStatement (sql) sont appelés plusieurs fois sur un seul objet de connexion?
Edit1: 6. Est-ce que l'utilisation de l'objet de déclaration de référence Weak / Soft aidera à empêcher la fuite?
Edit2: 1. Y a-t-il un moyen, je peux trouver tous les "statement.close ()" manquants dans mon projet? Je comprends que ce n'est pas une fuite de mémoire. Mais j'ai besoin de trouver une référence d'instruction (où close () n'est pas effectuée) éligible pour le garbage collection? Un outil disponible? Ou dois-je l'analyser manuellement?
S'il vous plaît, aidez-moi à le comprendre.
Solution
Pour trouver le curseur ouvert dans Oracle DB pour le nom d'utilisateur -VELU
Accédez à la machine ORACLE et démarrez sqlplus en tant que sysdba.
[oracle@db01 ~]$ sqlplus / as sysdba
Puis cours
SELECT A.VALUE,
S.USERNAME,
S.SID,
S.SERIAL#
FROM V$SESSTAT A,
V$STATNAME B,
V$SESSION S
WHERE A.STATISTIC# = B.STATISTIC#
AND S.SID = A.SID
AND B.NAME = 'opened cursors current'
AND USERNAME = 'VELU';
Si possible, veuillez lire ma réponse pour plus de compréhension de ma solution
for (String language : additionalLangs) {
SYS.V$OPEN_CURSOR
vue. Cela vous donnera non seulement le SID, mais également le texte SQL.Réponses:
ORA-01000, l'erreur maximum-open-cursors, est une erreur extrêmement courante dans le développement de bases de données Oracle. Dans le contexte de Java, cela se produit lorsque l'application tente d'ouvrir plus de ResultSets qu'il n'y a de curseurs configurés sur une instance de base de données.
Les causes courantes sont:
Erreur de configuration
Solution:
Fuite de curseur
Contexte
Cette section décrit une partie de la théorie derrière les curseurs et comment JDBC doit être utilisé. Si vous n'avez pas besoin de connaître l'arrière-plan, vous pouvez l'ignorer et aller directement à «Éliminer les fuites».
Qu'est-ce qu'un curseur?
Un curseur est une ressource sur la base de données qui contient l'état d'une requête, en particulier la position d'un lecteur dans un ResultSet. Chaque instruction SELECT possède un curseur et les procédures stockées PL / SQL peuvent ouvrir et utiliser autant de curseurs que nécessaire. Vous pouvez en savoir plus sur les curseurs sur Orafaq .
Une instance de base de données sert généralement plusieurs schémas différents , de nombreux utilisateurs différents ayant chacun plusieurs sessions . Pour ce faire, il dispose d'un nombre fixe de curseurs disponibles pour tous les schémas, utilisateurs et sessions. Lorsque tous les curseurs sont ouverts (en cours d'utilisation) et qu'une demande arrive qui nécessite un nouveau curseur, la demande échoue avec une erreur ORA-010000.
Recherche et définition du nombre de curseurs
Le numéro est normalement configuré par le DBA lors de l'installation. Le nombre de curseurs actuellement utilisés, le nombre maximum et la configuration sont accessibles dans les fonctions Administrateur d' Oracle SQL Developer . Depuis SQL, il peut être défini avec:
Association de JDBC dans la JVM aux curseurs de la base de données
Les objets JDBC ci-dessous sont étroitement associés aux concepts de base de données suivants:
JDBC est thread-safe: il est tout à fait normal de passer les différents objets JDBC entre les threads.
Par exemple, vous pouvez créer la connexion dans un thread; un autre thread peut utiliser cette connexion pour créer un PreparedStatement et un troisième thread peut traiter le jeu de résultats. La seule restriction majeure est que vous ne pouvez pas avoir plus d'un ResultSet ouvert sur un seul PreparedStatement à tout moment. Voir Oracle DB prend-il en charge plusieurs opérations (parallèles) par connexion?
Notez qu'une validation de base de données se produit sur une connexion, et donc tous les DML (INSERT, UPDATE et DELETE) sur cette connexion seront validés ensemble. Par conséquent, si vous souhaitez prendre en charge plusieurs transactions en même temps, vous devez avoir au moins une connexion pour chaque transaction simultanée.
Fermer les objets JDBC
Un exemple typique d'exécution d'un ResultSet est:
Notez comment la clause finally ignore toute exception déclenchée par close ():
Dans Java 7, Oracle a introduit l' interface AutoCloseable qui remplace la plupart des standards Java 6 par un bon sucre syntaxique.
Tenir des objets JDBC
Les objets JDBC peuvent être conservés en toute sécurité dans des variables locales, des instances d'objet et des membres de classe. Il est généralement préférable de:
Il existe cependant une exception: si vous utilisez des EJB ou un conteneur Servlet / JSP, vous devez suivre un modèle de threading strict:
Éliminer les fuites
Il existe un certain nombre de processus et d'outils disponibles pour aider à détecter et éliminer les fuites JDBC:
Pendant le développement - attraper les bogues tôt est de loin la meilleure approche:
Pratiques de développement: Les bonnes pratiques de développement doivent réduire le nombre de bogues dans votre logiciel avant qu'il ne quitte le bureau du développeur. Les pratiques spécifiques comprennent:
Analyse de code statique: utilisez un outil comme les excellents Findbugs pour effectuer une analyse de code statique. Cela ramasse de nombreux endroits où la fermeture () n'a pas été correctement gérée. Findbugs a un plugin pour Eclipse, mais il fonctionne également de manière autonome pour des opérations ponctuelles, a des intégrations dans Jenkins CI et d'autres outils de construction
Lors de l'exécution:
Holdability et engagement
Journalisation au moment de l'exécution.
Vous pouvez ajouter un pilote JDBC de débogage à votre projet (pour le débogage - ne le déployez pas réellement). Un exemple (je ne l'ai pas utilisé) est log4jdbc . Vous devez ensuite faire une analyse simple sur ce fichier pour voir quelles exécutions n'ont pas de fermeture correspondante. Le comptage des ouvertures et des fermetures doit mettre en évidence s'il y a un problème potentiel
D'autres pensées
Pouvez-vous utiliser WeakReferences pour gérer les connexions de fermeture?
Les références faibles et souples sont des moyens de vous permettre de référencer un objet d'une manière qui permet à la JVM de récupérer le référent à tout moment qu'elle juge bon (en supposant qu'il n'y a pas de chaînes de référence solides pour cet objet).
Si vous passez une ReferenceQueue dans le constructeur à la référence souple ou faible, l'objet est placé dans la ReferenceQueue lorsque l'objet est GC lorsqu'il se produit (si cela se produit du tout). Avec cette approche, vous pouvez interagir avec la finalisation de l'objet et vous pouvez fermer ou finaliser l'objet à ce moment.
Les références fantômes sont un peu plus étranges; leur but est uniquement de contrôler la finalisation, mais vous ne pouvez jamais obtenir de référence à l'objet d'origine, il sera donc difficile d'appeler la méthode close () dessus.
Cependant, il est rarement judicieux de tenter de contrôler le moment où le GC est exécuté (les références faibles, souples et fantômes vous informent après le fait que l'objet est mis en file d'attente pour GC). En fait, si la quantité de mémoire dans la JVM est grande (par exemple -Xmx2000m), vous risquez de ne jamais GC l'objet, et vous rencontrerez toujours l'ORA-01000. Si la mémoire JVM est petite par rapport aux exigences de votre programme, vous pouvez constater que les objets ResultSet et PreparedStatement sont mis en GC immédiatement après leur création (avant que vous puissiez les lire), ce qui échouera probablement votre programme.
TL; DR: Le mécanisme de référence faible n'est pas un bon moyen de gérer et de fermer les objets Statement et ResultSet.
la source
J'ajoute un peu plus de compréhension.
Connectez-vous en tant que sysdba.
Dans Putty (connexion Oracle):
Dans SqlPlus:
Nom d'utilisateur:
sys as sysdba
Définissez la valeur session_cached_cursors sur 0 afin qu'il n'ait pas de curseurs fermés.
Sélectionnez le jeu de valeurs OPEN_CURSORS existant par connexion dans DB
Vous trouverez ci-dessous la requête pour trouver la liste SID / connexions avec des valeurs de curseur ouvertes.
Utilisez la requête ci-dessous pour identifier les SQL dans les curseurs ouverts
Déboguez maintenant le code et profitez-en !!! :)
la source
Corrigez votre code comme ceci:
Êtes-vous sûr que vous fermez vraiment vos relevés, vos connexions et vos résultats?
Pour analyser les objets ouverts, vous pouvez implémenter un modèle de délégant, qui encapsule le code autour de vos objets statemant, connexion et résultat. Vous verrez donc si un objet sera fermé avec succès.
Un exemple pour: pStmt = obj. getConnection () .prepareStatement (sql);
la source
Si votre application est une application Java EE exécutée sur Oracle WebLogic en tant que serveur d'applications, une cause possible de ce problème est le paramètre Taille du cache de l' instruction dans WebLogic.
Si le paramètre Taille du cache des instructions pour une source de données particulière est à peu près égal ou supérieur au paramètre de nombre maximal de curseurs ouverts de la base de données Oracle, tous les curseurs ouverts peuvent être utilisés par les instructions SQL mises en cache qui sont maintenues ouvertes par WebLogic, ce qui dans l'erreur ORA-01000.
Pour résoudre ce problème, réduisez le paramètre Taille du cache de l'instruction pour chaque source de données WebLogic qui pointe vers la base de données Oracle pour qu'il soit nettement inférieur au paramètre de nombre maximal de curseurs sur la base de données.
Dans WebLogic 10 Admin Console, le paramètre Taille du cache de l'instruction pour chaque source de données se trouve dans Services (navigation gauche)> Sources de données> (source de données individuelle)> onglet Pool de connexions.
la source
J'avais moi aussi été confronté à ce problème.
J'utilisais Spring Framework avec Spring JDBC pour la couche dao.
Mon application avait l'habitude de fuir les curseurs d'une manière ou d'une autre et après quelques minutes environ, elle me donnait cette exception.
Après de nombreux débogages et analyses approfondis, j'ai trouvé qu'il y avait un problème avec l' indexation, la clé primaire et les contraintes uniques dans l'une des tables utilisées dans la requête que j'exécutais.
Mon application essayait de mettre à jour les colonnes indexées par erreur . Ainsi, chaque fois que mon application frappait la requête de mise à jour sur les colonnes indexées, la base de données essayait de faire la réindexation en fonction des valeurs mises à jour. Il fuyait les curseurs .
J'ai pu résoudre le problème en faisant une indexation appropriée sur les colonnes qui ont été utilisées pour rechercher dans la requête et en appliquant les contraintes appropriées le cas échéant.
la source
J'ai rencontré le même problème (ORA-01000) aujourd'hui. J'ai eu une boucle for dans le try {}, pour exécuter une instruction SELECT dans une base de données Oracle plusieurs fois (à chaque fois en changeant un paramètre), et dans le finalement {} j'ai eu mon code pour fermer Resultset, PreparedStatement et Connection comme d'habitude . Mais dès que j'ai atteint un nombre spécifique de boucles (1000), j'ai eu l'erreur Oracle concernant trop de curseurs ouverts.
Sur la base du message d'Andrew Alcock ci-dessus, j'ai apporté des modifications afin qu'à l' intérieur de la boucle, je ferme chaque jeu de résultats et chaque instruction après avoir obtenu les données et avant de recommencer, et cela a résolu le problème.
En outre, le même problème s'est produit dans une autre boucle d'instructions d'insertion, dans une autre base de données Oracle (ORA-01000), cette fois après 300 instructions. Encore une fois, il a été résolu de la même manière, de sorte que le PreparedStatement ou le ResultSet ou les deux comptent comme des curseurs ouverts jusqu'à ce qu'ils soient fermés.
la source
Avez-vous défini autocommit = true? Sinon, essayez ceci:
la source
requête pour trouver sql qui s'est ouvert.
la source
Ce problème se produit principalement lorsque vous utilisez le regroupement de connexions, car lorsque vous fermez la connexion, cette connexion revient au pool de connexions et tous les curseurs associés à cette connexion ne se ferment jamais car la connexion à la base de données est toujours ouverte. Donc, une alternative est de réduire le temps de connexion inactive des connexions dans le pool, ainsi peut-être chaque fois que la connexion reste inactive en connexion pendant 10 secondes, par exemple, la connexion à la base de données sera fermée et une nouvelle connexion sera créée pour être mise en pool.
la source
L'utilisation du traitement par lots entraînera moins de frais généraux. Consultez le lien suivant pour des exemples: http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm
la source
Dans notre cas, nous utilisions Hibernate et nous avions de nombreuses variables référençant la même entité mappée Hibernate. Nous étions en train de créer et de sauvegarder ces références en boucle. Chaque référence ouvrait un curseur et le maintenait ouvert.
Nous avons découvert cela en utilisant une requête pour vérifier le nombre de curseurs ouverts lors de l'exécution de notre code, en parcourant avec un débogueur et en commentant sélectivement les choses.
Quant à savoir pourquoi chaque nouvelle référence a ouvert un autre curseur - l'entité en question avait des collections d'autres entités mappées dessus et je pense que cela avait quelque chose à voir avec elle (peut-être pas seulement cela seul mais en combinaison avec la façon dont nous avions configuré le mode de récupération et paramètres de cache). Hibernate lui-même a eu des bugs autour de l'échec de la fermeture des curseurs ouverts, bien qu'il semble que ceux-ci aient été corrigés dans les versions ultérieures.
Comme nous n'avions pas vraiment besoin d'avoir autant de références dupliquées à la même entité de toute façon, la solution était d'arrêter de créer et de conserver toutes ces références redondantes. Une fois que nous avons fait cela, le problème en notre absence.
la source
J'ai eu ce problème avec ma source de données dans WildFly et Tomcat, en me connectant à un Oracle 10g.
J'ai constaté que dans certaines conditions, l'instruction n'était pas fermée même lorsque l'instruction.close () était invoquée. Le problème venait du pilote Oracle que nous utilisions: ojdbc7.jar. Ce pilote est destiné à Oracle 12c et 11g, et il semble avoir quelques problèmes lorsqu'il est utilisé avec Oracle 10g, donc je rétrograde vers ojdbc5.jar et maintenant tout fonctionne bien.
la source
J'ai rencontré le même problème parce que j'interrogeais db pour plus de 1000 itérations. J'ai utilisé try et enfin dans mon code. Mais obtenait toujours une erreur.
Pour résoudre ce problème, je viens de me connecter à oracle db et j'ai exécuté la requête ci-dessous:
ALTER SYSTEM SET open_cursors = 8000 SCOPE = LES DEUX;
Et cela a résolu mon problème immédiatement.
la source