2009-09-17 3 views
6

Nous utilisons Spring SimpleJdbcCall pour appeler des procédures stockées dans Oracle qui renvoient des curseurs. Il semble que SimpleJdbcCall ne ferme pas les curseurs et après un certain temps, les curseurs max ouverts sont dépassés.ORA-01000: Curseurs ouverts maximum dépassés lors de l'utilisation de Spring SimpleJDBCCall

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 

Il y a quelques autres personnes sur les forums qui ont expérimenté cela mais apparemment pas de réponses. Cela me ressemble comme un bug dans le support du printemps/oracle.

Ce bug est critique et pourrait avoir un impact sur notre utilisation future de Spring JDBC.

Est-ce que quelqu'un a rencontré un correctif - soit en dépistant le problème au code de ressort ou a trouvé une solution de contournement qui évite le problème?

Nous utilisons Spring 2.5.6.

Voici la nouvelle version du code à l'aide SimpleJdbcCall qui semble ne pas être fermer correctement le jeu de résultats que les rendements proc via un curseur:

... 
SimpleJdbcCall call = new SimpleJdbcCall(dataSource); 

Map params = new HashMap(); 
params.put("remote_user", session.getAttribute("cas_username")); 

Map result = call 
    .withSchemaName("urs") 
    .withCatalogName("ursWeb") 
    .withProcedureName("get_roles") 
    .returningResultSet("rolesCur", new au.edu.une.common.util.ParameterizedMapRowMapper()) 
    .execute(params); 
List roles = (List)result.get("rolesCur") 

L'ancienne version du code qui n'utilise pas Spring JDBC n'a pas ce problème:

oracleConnection = dataSource.getConnection(); 
callable = oracleConnection.prepareCall(
     "{ call urs.ursweb.get_roles(?, ?) }" ); 
callable.setString(1, (String)session.getAttribute("cas_username")); 
callable.registerOutParameter (2, oracle.jdbc.OracleTypes.CURSOR); 
callable.execute(); 
ResultSet rset = (ResultSet)callable.getObject(2); 
... do stuff with the result set 
if (rset != null) rset.close(); // Explicitly close the resultset 
if (callable != null) callable.close(); //Close the callable 
if (oracleConnection != null) oracleConnection.close(); //Close the connection 

Il semblerait que le printemps JDBC ne demande pas rset.close(). Si je commente cette ligne dans l'ancien code, après le test de chargement, nous obtenons la même exception de base de données.

+3

Veuillez poster un code indiquant comment vous utilisez SimpleJdbcCall. Il est extrêmement improbable qu'il s'agisse d'un bug au printemps, et plus probablement de la manière dont vous l'utilisez, en particulier si l'on considère la manière non standard qu'Oracle gère les jeux de résultats. – skaffman

+1

+1 avec skaffman. Si vous ne pouvez pas trouver le problème, essayez de construire un cas de test solide avant de signaler un bug à http://jira.springframework.org/ –

Répondre

7

Après beaucoup de tests, nous avons résolu ce problème. C'est une combinaison de la façon dont nous utilisions le framework Spring et le client Oracle et la DB Oracle.Nous étions en train de créer de nouveaux SimpleJDBCCalls qui utilisaient les appels de métadonnées du client Oracle JDBC qui étaient retournés comme des curseurs qui n'étaient pas fermés et nettoyés. Je considère cela comme un bug dans le framework Spring JDBC dans la façon dont il appelle les métadonnées mais ne ferme pas le curseur. Spring doit copier les méta-données hors du curseur et les fermer correctement. Je n'ai pas pris la peine d'ouvrir un problème jira avec le printemps parce que si vous utilisez les meilleures pratiques, le bug n'est pas exposé. L'ajustement de OPEN_CURSORS ou de l'un des autres paramètres est une mauvaise façon de résoudre ce problème et de retarder son apparition.

Nous avons travaillé autour d'elle/l'avons corrigé en déplaçant le SimpleJDBCCall dans un DAO singleton afin qu'il n'y ait qu'un seul curseur ouvert pour chaque proc d'oracle que nous appelons. Ces curseurs sont ouverts pour la durée de vie de l'application - que je considère comme un bug. Tant que OPEN_CURSORS est plus grand que le nombre d'objets SimpleJDBCCall, il n'y aura pas de problèmes.

+5

J'espère que vous l'avez signalé si vous le considérez comme un bug :) –

1

Je peux vous promettre que ce n'est pas le printemps. J'ai travaillé sur une application Spring 1.x qui a été mise en ligne en 2005 et qui n'a jamais fui depuis. (WebLogic 9., JDK 5). Vous ne fermez pas vos ressources correctement.

Utilisez-vous un pool de connexions? Quel serveur d'applications déployez-vous? Quelle version de Spring? Oracle? Java? Détails, s'il vous plaît.

-3

La solution n'est pas au printemps, mais dans Oracle: vous devez définir le paramètre d'initialisation OPEN_CURSORS à une valeur supérieure à la valeur par défaut 50.

Oracle - au moins-de 8i, peut-être il a changé - - réparait les objets JDBC PreparedStatement sauf si vous les laissiez ouverts. C'était cher, et la plupart des gens finissent par maintenir un pool fixe d'instructions ouvertes qui sont resoumises.

(en prenant un coup d'œil sur les docs 10i, ils notent explicitement que le pilote BEC cache PreparedStatements, donc je suppose que le pilote natif les reconstitue toujours à chaque fois)

+2

Ceci est une fuite de ressources, la solution à une fuite de ressources est d'arrêter fuite, ne pas ajouter plus d'eau. –

+1

@Andrew - merci d'avoir commenté votre downvote. Cependant, ayant travaillé avec Oracle depuis le début des années 1990, je maintiens ma réponse. Hors de la boîte, sa configuration n'est pas adaptée à une application complexe. En outre, l'OP utilise Spring, ce qui est très bon pour le nettoyage après lui-même. Il est toujours possible que le PO ait écrit une fuite de ressources quelque part, mais beaucoup moins probable que s'il faisait une gestion de connexion explicite. – kdgregory

+0

En relisant tous les messages, je vois que l'OP a posté la réponse acceptée deux mois après ma réponse, indiquant qu'il s'agissait en fait d'une fuite de ressources avec Spring. Cependant, étant donné que la fuite supposée était Spring tentant de mettre en cache des métadonnées, je vais me référer à mon deuxième paragraphe, et toujours à cette réponse. – kdgregory

-2

Oracle OPEN_CURSORS est la clé bien . Nous avons une petite application 24x7 contre Oracle XE avec seulement quelques curseurs apparemment ouverts. Il suffit de régler la valeur d'initialisation OPEN_CURSORS à> 300

+4

Il s'agit d'une fuite de ressources, la solution à une fuite de ressources est d'arrêter de fuir, pas ajouter plus d'eau. –

2

Il suffit de régler OPEN_CURSORS sur des valeurs de plus en plus élevées car il y a des préfixes et cela peut être juste un problème de bande passante votre code.

Je n'ai pas d'expérience avec le côté du printemps de cela, mais travaillé sur une application où nous avons eu beaucoup de problèmes avec des erreurs ORA-01000 et en ajustant constamment OPEN_CURSORS juste fait disparaître le problème un peu de temps ...

3

Eh bien, j'ai ce problème quand je lisais des BLOBs. La cause principale était que je mettais également à jour la table et que la clause Statement contenant update n'était pas fermée automatiquement. Nasty cursorleak mange tous les curseurs libres. Après l'appel explicite de statement.close() l'erreur disparaît.

Moral - toujours fermer tout, ne comptez pas sur la fermeture automatique après l'élimination de déclaration.

Questions connexes