2017-04-17 1 views
1

Ich bin mir nicht sicher, die beste Praxis dafür, aber mein Gesamtproblem ist, dass ich nicht herausfinden kann, warum meine Verbindung nicht schließt.Verbindung zu SqlServer nicht in für Schleife schließen java

Ich bin im Grunde durchlaufen eine Liste und dann fügen Sie sie in eine Tabelle ein. Bevor ich sie in eine Tabelle einfüge, überprüfe ich und stelle sicher, dass es kein Duplikat ist. Wenn dies der Fall ist, aktualisiere ich die Zeile, anstatt sie einzufügen. Bis jetzt kann ich nur 13 Iterationen zum Arbeiten bekommen, bevor das Debugging mir sagt, dass ich eine Verbindung hatte, die nicht nah ist.

Da ich 2 Verbindungen habe, habe ich Probleme herauszufinden, wo ich meine Verbindungen schließen soll, und ich versuchte, andere Beispiele zu verwenden, um zu helfen. Hier ist, was ich habe:

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

Das ist meine zusammengefasste Verbindung:

//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 

Meine Hauptfragen sind, bin ich zu schließen meine Verbindungen richtig? Ist mein Verbindungspool richtig eingerichtet? Sollte ich die Verbindung innerhalb der for-Schleife oder außerhalb schließen?

Ist mein Problem mit c3p0? Oder JTDS?

+1

IMHO, sollten Sie die Verbindung außerhalb der 'for' Schleife wurden zur Festlegung, dann zu schließen, wenn die Schleife beendet/Ausgänge. Andernfalls erhalten Sie bei jedem Durchlauf eine neue Verbindung. Ja, mit Pooling, das gemildert wird, aber es ist immer noch eine Menge Abwechslung, die vermieden werden kann. – alroc

+0

Tut mir leid, wenn das wie eine wirklich dumme Frage klingt, aber ist es sicher, eine vorbereitete Anweisung mehrmals auf der gleichen Verbindung wiederzuverwenden, bevor sie schließt? – arsarc

+1

Ja. Sie können die Anweisung möglicherweise sogar außerhalb der Schleife vorbereiten und die Parameter bei jeder Iteration einfach aktualisieren. Auch wenn Sie keine Verbindung zu zwei verschiedenen Datenquellen herstellen (und es sieht nicht so aus, wie Sie sind), können Sie möglicherweise "con2" löschen und "con" für alles verwenden. Potiential Micro-Optimierungen, aber wenn Sie das viel wiederholen, summiert sich das. – alroc

Antwort

1

Es ist großartig, dass Sie daran arbeiten, robust zu sein close() Ihre Ressourcen, aber das ist übermäßig kompliziert.

Sofern Sie nicht eine ziemlich alte Version von Java (etwas vor Java 7) verwenden, können Sie try-with-resources verwenden, was dieses Zeug wirklich vereinfacht. Das Arbeiten mit zwei verschiedenen Verbindungen in einer logischen Arbeitseinheit führt zu Missverständnissen. Ressourcen sollten so lokal wie möglich zu ihrer Nutzung als close() ed sein, anstatt alles bis zum Ende zu verschieben.

Ihre Ausnahmebehandlung ist gefährlich. Wenn eine Ausnahme auftritt, die Sie nicht verstehen, möchten Sie möglicherweise die Stapelüberwachung drucken, aber Ihr Code sollte die Tatsache signalisieren, dass alles, was Sie getan haben, nicht funktioniert hat. Sie schlucken die Exception und benachrichtigen sie sogar "Save Complete".

All dies gesagt, Ihr Leben könnte viel einfacher durch eine MERGE Anweisung, die I think SQL Server supports. Hier

ist eine (nicht getestet, nicht kompiliert) Beispiel Reorganisation:

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, ich habe meine Verbindungen in meinem Programm so umgeschrieben, dass sie wie Versuche mit Ressourcen arbeiten, und es scheint, als würden die Verbindungen schließen. Ich bin wirklich überrascht, dass, wenn ich Beispiele für die Erstellung von Verbindungen mit SQL nachschlagen habe ich noch nie mit Ressource in ihnen gefunden habe. Es war immer versuchen/fangen/endlich. Danke für diese Antwort. – arsarc

Verwandte Themen