2017-04-17 1 views
1

Je ne suis pas sûr de la meilleure pratique pour cela, mais mon problème global est que je n'arrive pas à comprendre pourquoi ma connexion ne se ferme pas. J'effectue une itération à travers une liste, puis je les insère dans une table. Avant de les insérer dans une table, je vérifie et je m'assure que ce n'est pas un doublon. si c'est le cas, je mets à jour la ligne au lieu de l'insérer. A partir de maintenant, je peux seulement obtenir 13 itérations à travailler avant que le débogage me laisse savoir que j'avais une connexion pas proche.La connexion à SqlServer ne se termine pas par la boucle Java

Depuis que j'ai 2 connexions, j'ai du mal à trouver où je suis supposé fermer mes connexions, et j'essayais d'utiliser d'autres exemples pour aider. Voici ce que je suis:

 Connection con = null; 
    PreparedStatement stmt = null; 
    PreparedStatement stmt2 = null; 
    ResultSet rs = null; 
    Connection con2 = null; 


    for (Object itemId: aList.getItemIds()){ 
     try { 
      con = cpds2.getConnection(); 
       stmt = con.prepareStatement("select [ID] from [DB].[dbo].[Table1] WHERE [ID] = ?"); 
       stmt.setInt(1, aList.getItem(itemId).getBean().getID()); 

       rs = stmt.executeQuery(); 
      //if the row is already there, update the data/ 

       if (rs.isBeforeFirst()){ 
        System.out.println("Duplicate"); 
        stmt2 = con2.prepareStatement("UPDATE [DB].[dbo].[Table1] SET " 
        + "[DateSelected]=GETDATE() where [ID] = ?"); 
        stmt2.setInt(1,aList.getItem(itemId).getBean().getID()); 
       stmt2.executeUpdate(); 
       }//end if inserting duplicate 
       else{ 
        con2 = cpds2.getConnection(); 
        System.out.println("Insertion"); 
        stmt.setInt(1, aList.getItem(itemId).getBean().getID()); 

        //Otherwise, insert them as if they were new 
        stmt2 = con.prepareStatement("INSERT INTO [DB].[dbo].[Table1] ([ID],[FirstName]," 
          + "[LastName],[DateSelected]) VALUES (?,?,?,?)"); 
        stmt2.setInt(1,aList.getItem(itemId).getBean().getID()); 
        stmt2.setString(2,aList.getItem(itemId).getBean().getFirstName()); 
        stmt2.setString(3,aList.getItem(itemId).getBean().getLastName()); 
        stmt2.setTimestamp(4, new Timestamp(new Date().getTime())); 
        stmt2.executeUpdate(); 
       }//End Else 
     }catch(Exception e){ 
       e.printStackTrace(); 
      }//End Catch 
     finally{ 
       try { if (rs!=null) rs.close();} catch (Exception e) {} 
      try { if (stmt2!=null) stmt2.close();} catch (Exception e) {} 
      try { if (stmt!=null) stmt.close();} catch (Exception e) {} 
      try { if (con2!=null) con2.close();} catch (Exception e) {} 
      try {if (con!=null) con.close();} catch (Exception e) {} 
      }//End Finally 

    } //end for loop 
    Notification.show("Save Complete"); 

Ceci est ma connexion commun:

//Pooled connection 
    cpds2 = new ComboPooledDataSource(); 

    try { 
     cpds2.setDriverClass("net.sourceforge.jtds.jdbc.Driver"); 
    } catch (PropertyVetoException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } //loads the jdbc driver 
    cpds2.setJdbcUrl("jdbc:jtds:sqlserver://SERVERNAME;instance=DB"); 
    cpds2.setUser("username"); 
    cpds2.setPassword("password"); 
    cpds2.setMaxStatements(180); 
    cpds2.setDebugUnreturnedConnectionStackTraces(true); //To help debug 
    cpds2.setUnreturnedConnectionTimeout(2); //to help debug 

Mes principales questions sont, suis-je fermais mes connexions droit? Mon pool de connexion est-il configuré correctement? Dois-je fermer la connexion à l'intérieur de la boucle for ou à l'extérieur?

Est-ce que mon problème avec c3p0? Ou JTDS?

+1

à mon humble avis, vous devez être établir la connexion en dehors de la boucle 'for', puis la fermeture complète lorsque la boucle/sorties. Sinon, vous obtenez une nouvelle connexion sur chaque boucle. Oui, avec la mise en commun qui est atténuée, mais il y a encore beaucoup de perte qui peut être évitée. – alroc

+0

Désolé, cette question est vraiment stupide, mais est-il possible de réutiliser plusieurs fois une instruction préparée sur la même connexion avant de la fermer? – arsarc

+1

Oui. Vous pouvez même préparer l'instruction en dehors de la boucle et mettre à jour les paramètres à chaque itération. En outre, à moins que vous ne vous connectiez à deux sources de données différentes (et que cela ne vous ressemble pas), vous pouvez supprimer "con2" et utiliser "con" pour tout. Micro-optimisations potentially, mais si vous bouclez beaucoup cela, il ajoute. – alroc

Répondre

1

Il est bon que vous travaillez à faire attention à vos ressources, mais c'est trop compliqué.

Sauf si vous utilisez une version plutôt ancienne de Java (antérieure à Java 7), vous pouvez utiliser try-with-resources, ce qui simplifie vraiment ce genre de choses. Travailler avec deux connexions différentes dans une unité de travail logique invite à des malentendus. Les ressources doivent être aussi localement que possible utilisées au lieu de tout reporter à la fin.

Votre gestion des exceptions est dangereuse. Si une exception survient et que vous ne comprenez pas, vous pouvez vouloir imprimer sa trace de pile, mais votre code devrait signaler que tout ce que vous faisiez ne fonctionnait pas. Vous avalez l'Exception, et même notifiez "Enregistrer Complet" malgré cela. Ceci étant dit, votre vie pourrait être rendue beaucoup plus facile par une déclaration MERGE, qui I think SQL Server supports.

Voici une réorganisation exemple (non testé, non compilé):

try (Connection con = cpds2.getConnection()) { 
    for (Object itemId: aList.getItemIds()){ 
     boolean id_is_present = false; 
     try (PreparedStatement stmt = con.prepareStatement("select [ID] from [DB].[dbo].[Table1] WHERE [ID] = ?")) { 
      stmt.setInt(1, aList.getItem(itemId).getBean().getID()); 
      try (ResultSet rs = stmt.executeQuery()) { 
       id_is_present = rs.next(); 
      } 
     } 
     if (id_is_present) { 
      System.out.println("Duplicate"); 
      try (PreparedStatement stmt = con.prepareStatement("UPDATE [DB].[dbo].[Table1] SET [DateSelected]=GETDATE() where [ID] = ?")) { 
       stmt.setInt(1,aList.getItem(itemId).getBean().getID()); 
       stmt.executeUpdate(); 
      } 
     } else { 
      System.out.println("Insertion"); 
      try (PreparedStatement stmt = con.prepareStatement("INSERT INTO [DB].[dbo].[Table1] ([ID],[FirstName], [LastName],[DateSelected]) VALUES (?,?,?,?)")) { 
       stmt.setInt(1,aList.getItem(itemId).getBean().getID()); 
       stmt.setString(2,aList.getItem(itemId).getBean().getFirstName()); 
       stmt.setString(3,aList.getItem(itemId).getBean().getLastName()); 
       stmt.setTimestamp(4, new Timestamp(new Date().getTime())); 
       stmt.executeUpdate(); 
      } 
     } 
    } 
    Notification.show("Save Complete");  
}  
+0

Ok, j'ai réécrit mes connexions dans mon programme pour travailler avec Try with resources, et il semble que les connexions se ferment. Je suis vraiment surpris que lorsque je cherche des exemples pour créer des connexions avec sql, je n'ai jamais trouvé Try with resource dedans. C'était toujours essayer/attraper/finalement. Merci pour cette réponse. – arsarc