2012-08-23 8 views
7

Unten ist der Code, den ich verwende, um multiple records(around 5000-7000) in der Oracle-Datenbank mit Prepared Statement einzufügen.Vorbereitetes Statement mehrmals effizient verwenden

Der Weg, den ich gerade mache, ist gut? Oder kann es besser mit einigen batch thing verbessern?

pstatement = db_connection.prepareStatement(PDSLnPConstants.UPSERT_SQL); 

for (Entry<Integer, LinkedHashMap<Integer, String>> entry : MAPPING.entrySet()) { 

    pstatement.setInt(1, entry.getKey()); 
    pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID)); 
    pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID)); 
    pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID)); 
    pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID)); 
    pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID)); 
    pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID)); 
    pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID)); 
    pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID)); 
    pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID)); 
    pstatement.executeUpdate(); 

    pstatement.clearParameters(); 
} 

Udpated Code, ich verwende: -

public void runNextCommand() { 

    Connection db_connection = null; 
    PreparedStatement pstatement = null; 
    int batchLimit = 1000; 
    boolean autoCommit = false; 

    try { 
     db_connection = getDBConnection(); 

     autoCommit = db_connection.getAutoCommit(); 
     db_connection.setAutoCommit(false); //Turn off autoCommit 
     pstatement = db_connection.prepareStatement(LnPConstants.UPSERT_SQL); // create a statement 

     for (Entry<Integer, LinkedHashMap<Integer, String>> entry : GUID_ID_MAPPING.entrySet()) { 
      pstatement.setInt(1, entry.getKey()); 
      pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID)); 
      pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID)); 
      pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID)); 
      pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID)); 
      pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID)); 
      pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID)); 
      pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID)); 
      pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID)); 
      pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID)); 
      pstatement.addBatch(); 

      batchLimit--; 

      if(batchLimit == 0){ 
       pstatement.executeBatch(); 
       pstatement.clearBatch(); 
       batchLimit = 1000; 
      } 
      pstatement.clearParameters(); 
     } 

    } catch (SQLException e) { 
     getLogger().log(LogLevel.ERROR, e); 
    } finally { 
     try { 
      pstatement.executeBatch(); 
      db_connection.commit(); 
      db_connection.setAutoCommit(autoCommit); 
     } catch (SQLException e1) { 
      getLogger().log(LogLevel.ERROR, e1.getMessage(), e1.fillInStackTrace()); 
     } 

     if (pstatement != null) { 
      try { 
       pstatement.close(); 
       pstatement = null; 
      } catch (SQLException e) { 
       getLogger().log(LogLevel.ERROR, e.getMessage(), e.fillInStackTrace()); 
      } 
     } 
     if (db_connection!= null) { 
      try { 
       db_connection.close(); 
       db_connection = null; 
      } catch (SQLException e) { 
       getLogger().log(LogLevel.ERROR, e.getMessage(), e.fillInStackTrace()); 
      } 
     } 
    } 
} 
+0

(Stellen Sie sicher, dass die Transaktionen korrekt verwendet werden. Andernfalls wird der angegebene Code "nicht gut" sein, selbst vorbereitete Anweisungen verwenden. Das heißt, INSERT/UPDATE ist "schnell". COMMIT ist "langsam".) –

Antwort

8

Sie denken kann addBatch() der Verwendung und eine Rückseite von Anweisungen in einem Schuss ausgeführt wird. Passen Sie auch, wie @pst in Ihrer Frage kommentierte, an.

Die Art und Weise Sie tun würde, ist wie folgt:

boolean autoCommit = connection.getAutoCommit(); 
try{ 
    connection.setAutoCommit(false //Turn off autoCommit 
    pstatement = db_connection.prepareStatement(PDSLnPConstants.UPSERT_SQL); 

    int batchLimit = 1000; 

    try{ 
     for (Entry<Integer, LinkedHashMap<Integer, String>> entry : MAPPING.entrySet()) { 
      pstatement.setInt(1, entry.getKey()); 
      pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID)); 
      pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID)); 
      pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID)); 
      pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID)); 
      pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID)); 
      pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID)); 
      pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID)); 
      pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID)); 
      pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID)); 

      pstatement.addBatch(); 
      batchLimit--; 

      if(batchLimit == 0){ 
       pstatement.executeBatch(); 
       pstatement.clearBatch 
       batchLimit = 1000; 
      } 
      pstatement.clearParameters(); 
     } 
    }finally{ 
     //for the remaining ones 
     pstatement.executeBatch(); 

     //commit your updates 
     connection.commit(); 
    } 
}finally{ 
    connection.setAutoCommit(autoCommit); 
} 

Die Idee ist, eine Grenze für die Batch-Updates festlegen und führen nur ein Datenbank-Update, wenn Sie eine bestimmte Grenze erreichen. Auf diese Weise begrenzen Sie einen Datenbankanruf auf einmal alle batchLimit, die Sie definiert haben. So wäre es schneller.

Beachten Sie auch für die transaction, ich habe gerade gezeigt, wie und wann zu commit. Dies ist möglicherweise nicht immer der richtige Punkt zu commit, da diese Entscheidung auf Ihrer Anforderung basieren würde. Möglicherweise möchten Sie auch eine rollback im Falle einer Ausnahme durchführen. Also müssen Sie sich entscheiden.

Werfen Sie einen Blick auf "Using Transaction" Tutorial, um ein besseres Bild von der Verwendung von transaction zu bekommen.

+0

Kannst du mir eine Beispielbasis für meinen Code geben, damit ich ein klares Bild davon bekomme, wie man 'addBatch()' hier benutzt? Es wird eine große Hilfe sein. – AKIWEB

+0

@ Nevzz03: Meine Antwort mit einem Beispielcode aktualisiert. Hoffe das hilft :) – Sujay

+0

Danke Sujay für die ausführliche Antwort.Schätze deine Hilfe. Ich habe gerade meine Frage mit dem vollständigen Code aktualisiert, den ich derzeit verwende, wie von Ihnen vorgeschlagen, nachdem Sie Änderungen vorgenommen haben. Kannst du einen Blick darauf werfen und mich wissen lassen, ob dir alles gut steht und ich nichts falsch mache? – AKIWEB

1

Ihr Stück Code scheint mir gut.

Nur für Code Sauberkeit, würde ich entry.getValue() in eine Variable setzen (nennen Sie es value).
Und es gibt keine Notwendigkeit, clearParameters() zu rufen.

Zuletzt, denken Sie daran, die vorbereitete Anweisung korrekt zu entsorgen, wenn Sie sie nicht mehr benötigen (close()).

+0

Danke gd1 für die Vorschläge. Warum brauchen Sie 'clearParameters()' nicht zu nennen? Ich wollte es nur vom Wissen her wissen. – AKIWEB

+1

Wenn Sie einen Parameter einstellen, wird der vorherige Wert gelöscht. :) – gd1

1

Ja, das Durchführen von Batch-Aktualisierungen würde Ihre Leistung erheblich verbessern. Einfach googeln, meine bevorzugte Antwort ist this one from Mkyong.com. Sonst sieht dein Code gut aus. "clearParameters()" ist nicht wirklich notwendig, es könnte sogar einige Prozessorzyklen verbrauchen. Wichtig: Wenn AutoCommit aktiviert ist, vergessen Sie nicht, es vorher zu deaktivieren, und aktivieren Sie es, nachdem Sie die Updates durchgeführt haben, dies bringt wieder eine enorme Verbesserung.

PS

Above Empfehlung basiert meiner Erfahrung auch auf. Ich habe gerade festgestellt, dass diese Frage bereits gestellt wurde here at Stackoverflow und die Antwort ist sehr detailliert. Weitere Informationen zu PreparedStatements und Batches finden Sie in der Oracle-Dokumentation here und über Transaktionen (AutoCommit) here.