web-dev-qa-db-fra.com

java.sql.SQLException: - ORA-01000: dépassement du nombre maximal de curseurs ouverts

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

  1. Le nombre maximal de curseurs ouverts correspond-il exactement au nombre de connexions JDBC ou existe-t-il également un lien avec les objets instruction et de jeu de résultats 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/resultset dans la base de données (comme des connexions)?
  3. Est-il conseillé d'utiliser l'objet instruction/resultset de variable d'instance au lieu d'objet instruction/resultset de méthode local dans un seul environnement threaded?
  4. L'exécution d'une instruction préparée dans une boucle est-elle à l'origine de 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ées plusieurs fois sur un objet de connexion unique?

Edit1:  6. L'utilisation de l'objet de déclaration Weak/Soft aidera-t-elle à prévenir les fuites? 

Edit2:  1. Y at-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 je dois trouver une référence d'instruction (où close () n'est pas exécuté) éligible pour le ramassage des ordures? 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 la base de données Oracle pour le nom d'utilisateur -VELU

Allez à la machine ORALCE et démarrez sqlplus en tant que sysdba.

[Oracle@db01 ~]$ sqlplus / as sysdba 

Puis courir

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 à la fin.

100
Kanagavelu Sugumar

ORA-01000, l'erreur de 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 communes sont:

  1. Erreur de configuration

    • Votre application interroge la base de données sur plus de threads que de curseurs sur la base de données. Dans un cas, votre pool de connexions et de threads est supérieur au nombre de curseurs de la base de données.
    • De nombreux développeurs ou applications sont connectés à la même instance de base de données (qui inclura 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 de 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 ne fait que retarder l'échec inévitable. Les fuites peuvent être détectées à l'aide de analyse de code statique , JDBC ou de la journalisation au niveau de l'application, et surveillance de la base de données .

Contexte

Cette section décrit une partie de la théorie sous-jacente aux curseurs et explique comment utiliser JDBC. Si vous n'avez pas besoin de connaître l'arrière-plan, vous pouvez ignorer ceci et aller directement à "Eliminer les fuites".

Qu'est-ce qu'un curseur?

Un curseur est une ressource de 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 a un curseur et les procédures stockées PL/SQL peuvent s'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, de nombreux tilisateurs chacun avec plusieurs sessions. Pour ce faire, un nombre fixe de curseurs est disponible pour tous les schémas, utilisateurs et sessions. Lorsque tous les curseurs sont ouverts (en cours d'utilisation) et qu'une requête nécessite un nouveau curseur, elle é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 maximal et la configuration sont accessibles dans les fonctions d’administrateur de Oracle SQL Developer . A partir de SQL, il peut être défini avec:

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

Relier JDBC de la machine virtuelle aux curseurs de la base de données

Les objets JDBC ci-dessous sont étroitement liés aux concepts de base de données suivants:

  • JDBC Connexion est la représentation du client d'une base de données session et fournit une base de données transactions. Une connexion ne peut avoir qu'une seule transaction ouverte à la fois (mais les transactions peuvent être imbriquées)
  • Un JDBC ResultSet ​​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 JDBC CallableStatement ​​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 sous la forme d'un jeu de résultats JDBC.

JDBC est thread-safe: il est tout à fait correct de passer les différents objets JDBC entre les threads.

Par exemple, vous pouvez créer la connexion dans un seul 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 principale restriction principale 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 a lieu sur une connexion et que tous les DML (INSERT, UPDATE et DELETE) de cette connexion seront validés ensemble. Par conséquent, si vous souhaitez prendre en charge plusieurs transactions simultanément, vous devez disposer d'au moins une connexion pour chaque transaction simultanée.

Fermeture d'objets JDBC

Voici un exemple typique d’exécution d’un ResultSet:

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 que la clause finally ignore toutes les exceptions déclenchées par close ():

  • Si vous fermez simplement le ResultSet sans try {} catch {}, cela pourrait échouer et empêcher la fermeture de l'instruction.
  • Nous voulons autoriser toute exception levée dans le corps de l'essai à se propager à l'appelant. Si, par exemple, vous créez et exécutez des instructions, n'oubliez pas de fermer chaque instruction de la boucle.

Dans Java 7, Oracle a introduit le interface auto-verrouillable , qui remplace la plupart du Java 6 par un sucre syntaxique de Nice.

Maintien d'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 réutilisés plusieurs fois sur une période plus longue, tels que Connections et PreparedStatements.
  • Utilisez les variables locales pour les ensembles de résultats, car ceux-ci sont obtenus, bouclés puis fermés, généralement dans le cadre d'une fonction unique.

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

  • Seul le serveur d'applications crée des threads (avec lesquels il traite les demandes entrantes)
  • Seul le serveur d'applications crée des connexions (obtenues à partir du pool de connexions).
  • Lorsque vous enregistrez des valeurs (état) entre des appels, vous devez faire très attention. Ne stockez jamais de valeurs dans vos propres caches ou membres statiques - ceci n'est pas sans danger entre clusters et autres conditions étranges, et le serveur d'applications peut faire des choses terribles pour vos données. Utilisez plutôt des beans stateful ou une base de données.
  • En particulier, never conserve les objets JDBC (Connections, ResultSets, PreparedStatements, etc.) sur différents appels distants - 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 états Préparé.

Éliminer les fuites

Un certain nombre de processus et d'outils sont disponibles pour aider à détecter et à éliminer les fuites JDBC:

  1. Pendant le développement, la meilleure approche consiste de loin à détecter les bogues.

    1. Pratiques de développement: de bonnes pratiques de développement devraient permettre de réduire le nombre de bogues dans votre logiciel avant qu'il ne quitte le bureau du développeur. Les pratiques spécifiques incluent:

      1. Programmation en binôme , pour éduquer ceux qui n’ont pas une expérience suffisante
      2. Code reviews parce que plusieurs yeux valent mieux qu'un
      3. Test unitaire ce qui signifie que vous pouvez utiliser n'importe quelle base de code à partir d'un outil de test rendant facile la reproduction des fuites.
      4. Utilisez bibliothèques existantes pour le regroupement de connexions plutôt que de créer votre propre
    2. Analyse de code statique: Utilisez un outil tel que l'excellent Findbugs pour effectuer une analyse de code statique. Cela détecte beaucoup d’endroits où la fermeture () n’a pas été gérée correctement. Findbugs a un plugin pour Eclipse, mais il fonctionne aussi de manière autonome pour des one-offs, il a des intégrations dans Jenkins CI et d'autres outils de construction

  2. À l'exécution:

    1. Holdability et commit

      1. Si la 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 en utilisant Connection.setHoldability () ou en utilisant la méthode surchargée Connection.createStatement ().
    2. Enregistrement au moment de l'exécution.

      1. Mettez de bonnes instructions de journal dans votre code. Celles-ci doivent être claires et compréhensibles pour que le client, le personnel de support et les coéquipiers puissent comprendre sans formation. Elles doivent être concises et inclure l’impression de l’état/des valeurs internes des variables et attributs clés afin que vous puissiez suivre la logique de traitement. Une bonne journalisation est essentielle au 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 effectuer une analyse simple sur ce fichier pour voir quelles exécutions n'ont pas de fermeture correspondante. Compter les ouvertures et les fermetures devrait mettre en évidence s'il y a un problème potentiel

        1. Surveiller la base de données. Surveillez votre application en cours d'exécution à l'aide d'outils tels que la fonction 'Surveiller SQL' de SQL Developer ou 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 vérifiez leur code 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 code SQL. Rechercher votre code et revoir.

D'autres pensées

Pouvez-vous utiliser WeakReferences pour gérer les connexions de fermeture?

Les références faibles et faibles sont des moyens de vous permettre de référencer un objet de manière à ce que la machine virtuelle Java puisse récupérer le référent à tout moment de la façon qu'elle juge appropriée (en supposant qu'aucune chaîne de référence forte ne soit associée à cet objet).

Si vous transmettez une référenceQueue dans le constructeur à la référence souple ou faible, l'objet est placé dans la référenceQueue lorsqu'il est GC'ed lorsqu'il survient (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-là.

Les références fantômes sont un peu plus bizarres; leur but est uniquement de contrôler la finalisation, mais vous ne pouvez jamais obtenir une référence à l'objet d'origine, il sera donc difficile d'appeler la méthode close () dessus.

Cependant, il est rarement judicieux d'essayer de contrôler le moment où le CPG est exécuté (Weak, Soft et PhantomReferences vous permettent de savoir 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 machine virtuelle est grande (par exemple -Xmx2000m), vous pourriez jamais GC, et vous rencontrerez toujours l'ORA-01000. Si la mémoire de la machine virtuelle Java est petite par rapport aux exigences de votre programme, vous constaterez peut-être que les objets ResultSet et PreparedStatement sont convertis immédiatement après la création (avant de pouvoir les lire), ce qui entraînera probablement l'échec de 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.

276
Andrew Alcock

J'ajoute un peu plus de compréhension.

  1. Cursor est seulement sur un objet de déclaration; Ce n'est ni resultSet ni l'objet de connexion. 
  2. Mais nous devons toujours fermer le jeu de résultats pour libérer de la mémoire Oracle. Toujours si vous ne fermez pas le résultat qui ne sera pas compté pour CURSEURS. 
  3. L'objet Closing Statement fermera aussi automatiquement l'objet resultset. 
  4. Le curseur sera créé pour toutes les instructions SELECT/INSERT/UPDATE/DELETE. 
  5. Chaque instance de base de données Oracle peut être identifiée à l'aide d'Oracle SID. De même, la base de données Oracle peut identifier chaque connexion à l'aide du SID de connexion. Les deux SID sont différents. 
  6. La session Oracle n’est donc rien d’autre qu’une connexion jdbc (tcp); qui n'est rien d'autre qu'un SID. 
  7. Si nous fixons le nombre maximal de curseurs à 500, cela ne vaut que pour une session/connexion/SID JDBC. 
  8. Ainsi, nous pouvons avoir de nombreuses connexions JDBC avec leurs no de curseurs (instructions) respectifs.
  9. Une fois que la machine virtuelle Java est terminée, toutes les connexions/curseurs seront fermés, OR JDBCConnection est fermé. CURSEURS par rapport à cette connexion sera fermé 

Loggin en tant que sysdba. 

Dans PuTTY (login Oracle):

  [Oracle@db01 ~]$ sqlplus / as sysdba

En SqlPlus:

Nom d'utilisateur: sys as sysdba

Définissez la valeur session_cached_cursors sur 0 pour éviter les curseurs fermés.

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

Sélectionner le jeu de valeurs OPEN_CURSORS existant par connexion dans la base de données

 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;

Ci-dessous se trouve la requête pour trouver la liste SID/connexions avec les 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'

Maintenant, déboguez le code et profitez-en !!! :)

24
Kanagavelu Sugumar

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()
} 

Etes-vous sûr, que vous fermez vraiment vos déclarations, connexions et résultats?

Pour analyser les objets ouverts, vous pouvez implémenter un motif de délégation qui enveloppe le code autour de vos objets statémant, connexion et résultat. Donc, vous verrez 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");
        }
    }
}
4
Mirko

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 Statement Cache Size de WebLogic.

Si le paramètre Taille du cache d'instructions d'une source de données particulière est égal ou supérieur au paramètre de nombre de curseurs ouverts de la base de données Oracle, tous les curseurs ouverts peuvent être utilisés par les instructions SQL en cache maintenues ouvertes par WebLogic, ce qui entraîne 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 pointant vers la base de données Oracle comme étant considérablement inférieur au paramètre de nombre de curseurs maximal défini dans la base de données.

Dans WebLogic 10 Admin Console, le paramètre Taille du cache des instructions de chaque source de données est disponible dans Services (navigation de gauche)> Sources de données> (source de données individuelle)> onglet Pool de connexions.

3
Jon Schneider

J'ai rencontré le même problème (ORA-01000) aujourd'hui. J'avais une boucle for dans le try {}, pour exécuter plusieurs fois une instruction SELECT dans une base de données Oracle (chaque fois que je changeais un paramètre), et enfin dans le}} j'avais le 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 pour que inside the loop, j’aie fermé chaque résultat et chaque instruction après avoir récupéré les données et avant de répéter la boucle, ce qui a résolu le problème.

De plus, le même problème est survenu dans une autre boucle d'instructions d'insertion, dans une autre base de données Oracle (ORA-01000), cette fois après 300 instructions. Une fois encore, il a été résolu de la même manière. Ainsi, PreparedStatement ou ResultSet, ou les deux, sont comptés comme des curseurs ouverts jusqu'à leur fermeture.

2
Kinnison84

requête pour trouver SQL qui a 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
1
Hlex

J'avais moi aussi été confronté à ce problème. L'exception ci-dessous venait

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 laisser fuir les curseurs et après quelques minutes, elle me donnait cette exception.

Après beaucoup de débogage et d’analyses approfondies, j’ai découvert qu’il y avait un problème avec l’indexation, la clé primaire et les contraintes uniques dans l’un des Table utilisés dans Query que j’exécutais. .

Mon application essayait de mettre à jour les Columns qui étaient par erreur Indexed . 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 réindexer en fonction du valeurs mises à jour. Il y avait une fuite de curseurs.

J'ai pu résoudre le problème en effectuant une indexation correcte sur les colonnes utilisées pour la recherche dans la requête et en appliquant les contraintes appropriées, le cas échéant.

1
Piyush Verma

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 
1
paweloque

Dans notre cas, nous utilisions Hibernate et de nombreuses variables faisaient référence à la même entité mappée Hibernate. Nous étions en train de créer et de sauvegarder ces références dans une boucle. Chaque référence ouvrait un curseur et le laissait ouvert.

Nous avons découvert cela en utilisant une requête pour vérifier le nombre de curseurs ouverts tout en exécutant notre code, en passant en revue avec un débogueur et en commentant sélectivement les choses.

Pourquoi chaque nouvelle référence ouvrait-elle un autre curseur? L'entité en question avait des collections d'autres entités mappées sur celle-ci et je pense que cela y était pour quelque chose. paramètres de cache). Hibernate lui-même a eu des bugs qui empêchaient de fermer ouvrir les curseurs, bien qu'il semble que ceux-ci aient été corrigés dans les versions ultérieures.

Comme nous n'avions de toute façon pas besoin d'avoir autant de références dupliquées à la même entité, la solution consistait à cesser de créer et de conserver toutes ces références redondantes. Une fois que nous avons fait le problème lorsque nous sommes partis.

0
dshiga

J'ai eu ce problème avec ma source de données dans WildFly et Tomcat, la connexion à 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 concernait le pilote Oracle que nous utilisions: ojdbc7.jar. Ce pilote est destiné aux Oracle 12c et 11g, et il semble que certains problèmes se posent lorsqu’il est utilisé avec Oracle 10g. C’est pourquoi je rétrograde en ojdbc5.jar et tout fonctionne correctement.

0
gilbertoag

J'ai rencontré le même problème parce que je demandais à la base de données depuis plus de 1000 itérations… .. J'ai utilisé try et finalement dans mon code Mais obtenait toujours une erreur.

Pour résoudre ce problème, je viens de me connecter à Oracle db et d’exécuter la requête ci-dessous:

ALTER SYSTEM SET open_cursors = 8000 SCOPE = BOTH;

Et cela a résolu mon problème immédiatement.

0
RArora

Ce problème se produit principalement lorsque vous utilisez le regroupement de connexions, car lorsque vous fermez une connexion, cette connexion est rétablie dans le pool de connexions et tous les curseurs associés à cette connexion ne sont jamais fermés, car la connexion à la base de données est toujours ouverte. réduisez le temps de connexion inactif des connexions dans le pool. Ainsi, chaque fois que la connexion est inactive pendant 10 secondes, la connexion à la base de données sera fermée et une nouvelle connexion créée pour la mise en pool. 

0
Raveesh Badoni

L'utilisation du traitement par lots entraînera moins de temps système. Voir le lien suivant pour des exemples: http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm

0
Manjunath