java.sql.SQLException: - ORA-01000: maximum de curseurs ouverts dépassés

115

Je reçois une exception SQL ORA-01000. J'ai donc quelques questions à ce sujet.

  1. 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)
  2. 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)?
  3. 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?
  4. 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 
    
  5. 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

Kanagavelu Sugumar
la source
Pouvez-vous publier votre code complet? Il serait intéressant de voir où fermez-vous les accolades d'ouverture ouvertes pourfor (String language : additionalLangs) {
Jåcob
@ Kanagavelu Sugumar: pourquoi ne pas poser 5 questions différentes en SO?
Jayan
1
Voici une réponse que j'ai trouvée très utile: stackoverflow.com/a/4507507/501113
chaotic3quilibrium
Veuillez voir si la réponse est utile: stackoverflow.com/questions/34716456/…
Manu
Pour rechercher les curseurs ouverts dans Oracle, vous pouvez également consulter la SYS.V$OPEN_CURSORvue. Cela vous donnera non seulement le SID, mais également le texte SQL.
Basse

Réponses:

291

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:

  1. Erreur de configuration

    • Vous avez plus de threads dans votre application interrogeant la base de données que de curseurs sur la base de données. Un cas est celui où vous avez une connexion et un pool de threads plus grands que le nombre de curseurs de la base de données.
    • Vous avez de nombreux développeurs ou applications connectés à la même instance de base de données (qui comprendra probablement de nombreux schémas) et, ensemble, vous utilisez trop de connexions.
    • Solution:

  2. Fuite de curseur

    • Les applications ne ferment pas les ResultSets (dans JDBC) ou les curseurs (dans les procédures stockées sur la base de données)
    • Solution : les fuites de curseur sont des bogues; l'augmentation du nombre de curseurs sur la base de données retarde simplement l'échec inévitable. Les fuites peuvent être détectées à l'aide de l'analyse de code statique , de la journalisation JDBC ou au niveau de l'application et de la surveillance de la base de données .

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:

ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;

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 Connection est la représentation client d'une session de base de données et fournit des transactions de base de données . Une connexion ne peut avoir qu'une seule transaction ouverte à la fois (mais les transactions peuvent être imbriquées)
  • Un ResultSet JDBC est pris en charge par un seul curseur sur la base de données. Lorsque close () est appelé sur le ResultSet, le curseur est relâché.
  • Un CallableStatement JDBC appelle une procédure stockée sur la base de données, souvent écrite en PL / SQL. La procédure stockée peut créer zéro ou plusieurs curseurs et peut renvoyer un curseur en tant que ResultSet JDBC.

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:

Statement stmt = conn.createStatement();
try {
    ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
    try {
        while ( rs.next() ) {
            System.out.println( "Name: " + rs.getString("FULL_NAME") );
        }
    } finally {
        try { rs.close(); } catch (Exception ignore) { }
    }
} finally {
    try { stmt.close(); } catch (Exception ignore) { }
}

Notez comment la clause finally ignore toute exception déclenchée par close ():

  • Si vous fermez simplement le ResultSet sans essayer {} catch {}, il peut échouer et empêcher la fermeture de l'instruction
  • Nous voulons permettre à toute exception déclenchée dans le corps de la tentative de se propager à l'appelant. Si vous avez une boucle sur, par exemple, la création et l'exécution d'instructions, n'oubliez pas de fermer chaque instruction dans la boucle.

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:

  • Utilisez une instance d'objet ou des membres de classe pour contenir des objets JDBC qui sont réutilisés plusieurs fois sur une période plus longue, tels que Connections et PreparedStatements
  • Utilisez des variables locales pour les ResultSets, car ils sont obtenus, bouclés puis fermés généralement dans le cadre d'une seule fonction.

Il existe cependant une exception: si vous utilisez des EJB ou un conteneur Servlet / JSP, vous devez suivre un modèle de threading strict:

  • Seul le serveur d'applications crée des threads (avec lesquels il gère les demandes entrantes)
  • Seul le serveur d'applications crée des connexions (que vous obtenez à partir du pool de connexions)
  • Lors de l'enregistrement des valeurs (état) entre les appels, vous devez être très prudent. Ne stockez jamais de valeurs dans vos propres caches ou membres statiques - ce n'est pas sûr entre les clusters et d'autres conditions étranges, et le serveur d'applications peut faire des choses terribles à vos données. Utilisez plutôt des beans avec état ou une base de données.
  • En particulier, ne gardez jamais d' objets JDBC (Connexions, ResultSets, PreparedStatements, etc.) sur différentes invocations à distance - laissez le serveur d'applications gérer cela. Le serveur d'applications fournit non seulement un pool de connexions, il met également en cache vos PreparedStatements.

Éliminer les fuites

Il existe un certain nombre de processus et d'outils disponibles pour aider à détecter et éliminer les fuites JDBC:

  1. Pendant le développement - attraper les bogues tôt est de loin la meilleure approche:

    1. 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:

      1. Programmation en binôme , pour éduquer ceux qui n'ont pas d'expérience suffisante
      2. Revues de code parce que plusieurs yeux valent mieux qu'un
      3. Test unitaire, ce qui signifie que vous pouvez exercer tout ou partie de votre base de code à partir d'un outil de test qui rend la reproduction des fuites triviale
      4. Utilisez les bibliothèques existantes pour le regroupement de connexions plutôt que de créer les vôtres
    2. 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

  2. Lors de l'exécution:

    1. Holdability et engagement

      1. Si le holdability ResultSet est ResultSet.CLOSE_CURSORS_OVER_COMMIT, le ResultSet est fermé lorsque la méthode Connection.commit () est appelée. Cela peut être défini à l'aide de Connection.setHoldability () ou de la méthode surchargée Connection.createStatement ().
    2. Journalisation au moment de l'exécution.

      1. Mettez de bonnes déclarations de journal dans votre code. Celles-ci doivent être claires et compréhensibles afin que le client, le personnel d'assistance et les coéquipiers puissent comprendre sans formation. Ils doivent être concis et inclure l'impression de l'état / des valeurs internes des variables clés et des attributs afin que vous puissiez suivre la logique de traitement. Une bonne journalisation est fondamentale pour le débogage des applications, en particulier celles qui ont été déployées.
      2. 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

        1. Surveillance de la base de données. Surveillez votre application en cours d'exécution à l'aide d'outils tels que la fonction SQL Developer 'Monitor SQL' ou le TOAD de Quest . La surveillance est décrite dans cet article . Pendant la surveillance, vous interrogez les curseurs ouverts (par exemple à partir de la table v $ sesstat) et révisez leur SQL. Si le nombre de curseurs augmente et (surtout) devient dominé par une instruction SQL identique, vous savez que vous avez une fuite avec ce SQL. Recherchez votre code et révisez.

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.

Andrew Alcock
la source
3
Si vous créez des instructions dans une boucle, assurez-vous qu'elle est fermée dans la boucle sinon vous finirez par fermer uniquement la dernière instruction.
basiljames
Merci, Basiljames. Il suffit de modifier la réponse pour ajouter le point que vous avez fait.
Andrew Alcock
@ Andrew Alcock Merci beaucoup! Andrew. Pourriez-vous s'il vous plaît répondre au 6e également.
Kanagavelu Sugumar
@AndrewAlcock S'il vous plaît .. s'il vous plaît .. s'il vous plaît .. répondez également à ma 7ème question. Depuis notre projet, nous sommes confrontés à ORA-01000 très fréquemment lors des tests de charge. Vos contributions sont plus précieuses pour moi. Merci beaucoup d'avance !!
Kanagavelu Sugumar
RE: 7 - vous pouvez essayer la recherche de proximité en utilisant un outil tel que grep. Lorsque vous reconnaissez un SQL (sélectionner, insérer, mettre à jour, supprimer), voyez la proximité du mot close () à côté de l'instruction. Si la proximité est plus éloignée que prévu, cela pourrait être un moyen de rechercher où elle est manquante. lightboxtechnologies.com/2012/07/27/…
Dim
28

J'ajoute un peu plus de compréhension.

  1. Le curseur concerne uniquement un objet d'instruction; Ce n'est ni resultSet ni l'objet de connexion.
  2. Mais nous devons quand même fermer l'ensemble de résultats pour libérer de la mémoire oracle. Toujours si vous ne fermez pas l'ensemble de résultats qui ne sera pas compté pour CURSORS.
  3. L'objet Instruction de fermeture fermera également automatiquement l'objet du jeu de résultats.
  4. Le curseur sera créé pour toutes les instructions SELECT / INSERT / UPDATE / DELETE.
  5. Chaque instance ORACLE DB peut être identifiée à l'aide d'Oracle SID; de même, ORACLE DB peut identifier chaque connexion à l'aide du SID de connexion. Les deux SID sont différents.
  6. Ainsi, la session ORACLE n'est rien d'autre qu'une connexion jdbc (tcp); qui n'est rien d'autre qu'un SID.
  7. Si nous définissons le nombre maximal de curseurs sur 500, ce n'est que pour une session / connexion / SID JDBC.
  8. Nous pouvons donc avoir de nombreuses connexions JDBC avec leur nombre respectif de curseurs (instructions).
  9. Une fois la JVM terminée, toutes les connexions / curseurs seront fermés, OU JDBCConnection est fermée CURSORS par rapport à cette connexion seront fermés.

Connectez-vous en tant que sysdba.

Dans Putty (connexion Oracle):

  [oracle@db01 ~]$ sqlplus / as sysdba

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.

 alter session set session_cached_cursors=0
 select * from V$PARAMETER where name='session_cached_cursors'

Sélectionnez le jeu de valeurs OPEN_CURSORS existant par connexion dans DB

 SELECT max(a.value) as highest_open_cur, p.value as max_open_cur FROM v$sesstat a, v$statname b, v$parameter p WHERE a.statistic# = b.statistic# AND b.name = 'opened cursors current' AND p.name= 'open_cursors'  GROUP BY p.value;

Vous trouverez ci-dessous la requête pour trouver la liste SID / connexions avec des valeurs de curseur ouvertes.

 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 = 'SCHEMA_NAME_IN_CAPS'

Utilisez la requête ci-dessous pour identifier les SQL dans les curseurs ouverts

 SELECT oc.sql_text, s.sid 
 FROM v$open_cursor oc, v$session s
 WHERE OC.sid = S.sid
 AND s.sid=1604
 AND OC.USER_NAME ='SCHEMA_NAME_IN_CAPS'

Déboguez maintenant le code et profitez-en !!! :)

Kanagavelu Sugumar
la source
1
Voici une autre requête qui semble bien fonctionner: stackoverflow.com/a/2560415/32453
rogerdpack
4

Corrigez votre code comme ceci:

try
{ //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
{ //finally starts
   pStmt.close()
} 

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

    class obj{ 

    public Connection getConnection(){
    return new ConnectionDelegator(...here create your connection object and put it into ...);

    } 
}


class ConnectionDelegator implements Connection{
    Connection delegates;

    public ConnectionDelegator(Connection con){
       this.delegates = con;
    }

    public Statement prepareStatement(String sql){
        return delegates.prepareStatement(sql);
    }

    public void close(){
        try{
           delegates.close();
        }finally{
           log.debug(delegates.toString() + " was closed");
        }
    }
}
Mirko
la source
3

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.

Jon Schneider
la source
1
Hibernate a également un cache de déclaration. Voir aussi developer.jboss.org/wiki/…
Pino
3

J'avais moi aussi été confronté à ce problème.

java.sql.SQLException: - ORA-01000: maximum open cursors exceeded

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.

Piyush Verma
la source
2

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.

Kinnison84
la source
Cela ne semble pas correct. Spring documents qu'il est responsable de la fermeture des ResultSets ( docs.spring.io/spring/docs/current/spring-framework-reference/… ).
Ryan
juste pour clarifier, dans ces exemples, je n'utilisais pas Spring.
Kinnison84
1

Avez-vous défini autocommit = true? Sinon, essayez ceci:

{ //method try starts  
    String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
    Connection conn = obj.getConnection()
    pStmt = conn.prepareStatement(sql);

    for (String language : additionalLangs) {
        pStmt.setLong(1, subscriberID);
        pStmt.setInt(2, Integer.parseInt(language));
        pStmt.execute();
        conn.commit();
    }
} //method/try ends { 
    //finally starts
    pStmt.close()
} //finally ends 
paweloque
la source
Pourriez-vous aussi répondre aux autres questions?
Kanagavelu Sugumar
2
Autocommit ne ferme pas les connexions - il valide uniquement automatiquement chaque instruction immédiatement après l'exécution. Si vous utilisez l'autocommit, vous n'obtenez pas de valeur à partir de l'une des propriétés les plus importantes de la base de données - les transactions. Vous pouvez envisager d'utiliser une base de données NoSQL à la place.
Andrew Alcock
1

requête pour trouver sql qui s'est ouvert.

SELECT s.machine, oc.user_name, oc.sql_text, count(1) 
FROM v$open_cursor oc, v$session s
WHERE oc.sid = s.sid
and S.USERNAME='XXXX'
GROUP BY user_name, sql_text, machine
HAVING COUNT(1) > 2
ORDER BY count(1) DESC
Hlex
la source
1

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.

Raveesh Badoni
la source
0

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.

dshiga
la source
0

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.

gilbertoag
la source
0

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.

RArora
la source
Cela a soulagé certains symptômes mais n'a pas vraiment résolu le problème. Vous devez corriger votre code pour qu'il ferme les curseurs une fois qu'il en a terminé avec eux.
APC