2015-12-18 3 views
1

J'ai un problème, le code ci-dessous fonctionne bien si je l'exécute sans la propriété autoCommit, mais je préfère l'exécuter comme une transaction, le code insère essentiellement les informations d'en-tête d'un article, puis la liste de tous les articles qui lui sont associés (c'est donc comme une relation un-à-plusieurs), donc je pourrais commettre tout en une fois plutôt que d'abord les informations sur l'article et ensuite ses articles. Le problème est que lorsque je tends la cn.commit() la ligne, je reçois une exception qui dit « Déclaration fermée »java.sql.SQLException Fermé Déclaration

méthode d'insertion de base de données

public static void addArticle(Article article) throws SQLException { 
      Connection cn = null; 
      PreparedStatement ps = null; 
      StringBuffer insert = new StringBuffer(); 
      StringBuffer itemsSQL = new StringBuffer(); 

      try { 
        article.setArticleSortNum(getNextArticleNum(article.getShopId())); 
        article.setArticleId(DAOHelper.getNextId("article_id_sequence")); 

        cn = DBHelper.makeConnection(); 
        cn.setAutoCommit(false); 

        insert.append("insert query for article goes here"); 
        ps = cn.prepareStatement(insert.toString()); 
        int i = 1; 
        ps.setLong(i, article.getArticleId()); i++; 
        ps.setLong(i, article.getShopId()); i++; 
        ps.setInt(i, article.getArticleNum()); i++; 
        // etcetera... 
        ps.executeUpdate(); 

        itemsSQL.append("insert query for each line goes here"); 
        itemStatement = cn.prepareStatement(itemsSQL.toString()); 
        for(Article item : article.getArticlesList()) { 

         item.setArticleId(article.getArticleId()); 
         i= 1; 
         itemStatement.setLong(i, item.getArticleId()); i++; 
         itemStatement.setInt(i, item.getItemsOnStock()); i++; 
         itemStatement.setInt(i, item.getQuantity()); i++; 
         // etcetera... 
         itemStatement.executeUpdate(); 

        } 
        cn.commit(); 

      } catch (SQLException e) { 
        cn.rollback(); 
        log.error(e.getMessage()); 
        throw e; 
      } 
      finally { 
        DBHelper.releasePreparedStatement(ps); 
        DBHelper.releasePreparedStatement(itemStatement); 
        DBHelper.releaseConnection(cn); 
      } 
     } 

J'ai aussi l'insertion des articles où le Pour est en cours d'exécution avec addBatch() puis executeBatch mais aussi la même erreur Closed Statement en atteignant cn.commit() ... Je ne comprends pas pourquoi sa fermeture, toutes les connexions et tout est libéré dans la clause finally, donc j'ai l'impression que je suis faire une erreur fondamentale, je ne suis pas au courant de ... Des idées? Merci d'avance!

EDIT: Voici la trace de pile:

java.sql.SQLException: Déclaration fermé à oracle.jdbc.dbaccess.DBError.throwSqlException (DBError.java:189) à oracle.jdbc. dbaccess.DBError.throwSqlException (DBError.java:231) à oracle.jdbc.dbaccess.DBError.throwSqlException (DBError.java:294) à oracle.jdbc.driver.OracleStatement.ensureOpen (OracleStatement.java:6226) à Oracle.jdbc.driver.OraclePreparedStatement.sendBatch (OraclePreparedStatement.java:592) at oracle.jdbc.driver.OracleConnection.commit (OracleConnection.java:1376) à com.evermind.sql.FilterConnection.commit (FilterConnection.java:201) à com.evermind.sql.OrionCMTConnection.commit (OrionCMTConnection. java: 461) à com.evermind.sql.FilterConnection.commit (FilterConnection.java:201) à com.dao.ArticlesDAO.addArticle (ArticlesDAO.java:571) à com.action.registry.CustomBaseAction.execute (CustomBaseAction.java:57) à org.apache.struts.action.RequestProcessor.processActionPerform (RequestProcessor.java:431) à org.apache.struts.action.RequestProcessor.process (RequestProcessor.java:236) à org.apache.struts.ac tion.ActionServlet.process (ActionServlet.java:1196) à org.apache.struts.action.ActionServlet.doPost (ActionServlet.java:432) à javax.servlet.http.HttpServlet.service (HttpServlet.java:760) à javax.servlet.http.HttpServlet.service (HttpServlet.java:853) à com.evermind.server.http.ServletRequestDispatcher.invoke (ServletRequestDispatcher.java:765) à com.evermind.server.http. ServletRequestDispatcher.forwardInternal (ServletRequestDispatcher.java:317) à com.evermind.server.http.HttpRequestHandler.processRequest (HttpRequestHandler.java:790) à com.evermind.server.http.HttpRequestHandler.run (HttpRequestHandler.java: 270) à com.evermind.server.http.HttpRequestHandler.run (HttpRequestHandler.java:112) à com.evermind.util.ReleasableResourcePooledExecutor $ MyWorker.run (ReleasableResourcePooledExecutor.java:192) à java.lang.Thread.run (Source inconnue)

EDIT 2:

Ce sont les paramètres dans la configuration de la source de données du conducteur, je pensais que le processus de débogage peut être ce qui en fait le temps, mais la finition même en moins d'une seconde lance le déclaration fermée exception

min-connections="20" 
max-connections="200" 
inactivity-timeout="20" 
stmt-cache-size="40"/> 
+0

Pouvez-vous s'il vous plaît publier la pile complète de l'exception? – zerocool

+0

J'ai édité la question et ajouté la trace de la pile – Ricardo

Répondre

2

il est généralement préférable de créer une déclaration, utilisez-le et fermez-le dès que possible, et il ne fait aucun mal à le faire avant que la transaction s'engage ted. À la lecture du manuel d'Oracle sur le modèle de traitement par lots, il semble que l'ouverture simultanée de plusieurs instructions puisse poser problème. Je voudrais essayer de fermer l'objet ps avant de travailler avec le itemStatement, puis déplacer l'initialisation

itemStatement = cn.prepareStatement(itemsSQL.toString()); 

directement au-dessus de la boucle, et aussi se déplacer où vous fermez le itemStatement immédiatement après la boucle:

PreparedStatement itemStatement = cn.prepareStatement(itemsSQL.toString()); 
try { 
    for(Article item : article.getArticlesList()) { 
     item.setArticleId(article.getArticleId()); 
     i= 1; 
     itemStatement.setLong(i, item.getArticleId()); i++; 
     itemStatement.setInt(i, item.getItemsOnStock()); i++; 
     itemStatement.setInt(i, item.getQuantity()); i++; 
        // etcetera... 
     itemStatement.executeUpdate(); 
    } 
} finally { 
    DBHelper.releasePreparedStatement(itemStatement); 
} 

Il semble que ce qui se passe est que vous avez défini un paramètre de traitement par lots sur la connexion qui provoque la connexion pour tenter de trouver des affaires inachevées dans l'instruction à terminer; c'est trouver la déclaration est déjà fermée et la connexion se plaint à ce sujet. C'est bizarre parce qu'au moment où le commit souffle sur vous le code n'a pas atteint le point où l'instruction est fermée.

La lecture des modèles de traitement par lots Oracle peut s'avérer utile. Vérifiez également la version du pilote JDBC et assurez-vous qu'elle correspond à la version d'Oracle que vous utilisez, et vérifiez si des mises à jour sont disponibles.

+0

Cela ressemblait vraiment à ça marcherait! Mais j'ai juste la même exception exacte :( – Ricardo

+0

J'ai mis à jour les paramètres timeout/connections le fichier de configuration a – Ricardo

+0

@Ricardo: ok .Voyez si ma mise à jour est utile.Egalement si vous avez plus de détails sur le batching dans le code ou dans la configuration pour la connexion s'il vous plaît ajouter ceux à la question –