Dieser Artikel beschreibt die Methode der Hibernate -Batch -Verarbeitung massiver Daten. Teilen Sie es für Ihre Referenz wie folgt weiter:
Die Verarbeitung von Hibernate -Batch -Verarbeitung massive Mengen sind aus der Perspektive der Leistung tatsächlich unerwünscht und werden viel Gedächtnis verschwendet. Aus seinem Mechanismus überprüft Hibernate zuerst die Daten, die den Bedingungen erfüllen, sie in den Speicher bringen und dann Vorgänge ausführt. Die Leistung ist im tatsächlichen Gebrauch sehr unbefriedigend. In meiner tatsächlichen Verwendung sind die Daten der folgenden dritten Optimierungslösung: 100.000 Datenstücke werden in die Datenbank eingefügt, die etwa 30 Minuten dauert. Haha, schwach. (Ich habe 1000.000 Daten in 10 Minuten eingefügt (die Felder sind relativ klein))
Es gibt drei Möglichkeiten, damit umzugehen, um Leistungsprobleme zu lösen:
1: Umgehen Sie die Hibernate -API und verwenden Sie die JDBC -API direkt. Diese Methode hat eine bessere Leistung. Es ist auch das schnellste.
2: Verwenden Sie gespeicherte Verfahren.
3: Verwenden Sie die Hibernate -API, um eine regelmäßige Chargenverarbeitung durchzuführen. Es kann Änderungen geben, und die Änderung wird sich ändern. Wenn wir einen bestimmten Betrag finden, können wir die Daten nach Abschluss der Operation Session.flush () rechtzeitig löschen. Session.evict (xx -Objektsatz); Dies kann auch einige Leistungsverluste sparen. Diese "bestimmte Menge" muss als quantitative Referenz anhand der tatsächlichen Bedingungen verwendet werden. Im Allgemeinen etwa 30-60, aber der Effekt ist immer noch nicht ideal.
1: Benden Sie die Hibernate -API und machen Sie sie direkt durch die JDBC -API. Diese Methode hat eine bessere Leistung und die schnellste. (Das Beispiel ist eine Aktualisierungsoperation)
Transaktion TX = Session.BeginTransaction (); // Beachten Sie, dass Sie die Hibernate -Transaktionsgrenzeverbindung verwenden conn = session.connection (); PrepectStatement STMT = Conn.PreeParedStatement ("Kunde als C -Set c.sarlary = c.sarlary+1, wobei c.sarlary> 1000"); stmt.excuteUpdate (); tx.commit (); // Beachten Sie, dass Sie die Hibernate -Transaktionsgrenze verwenden In diesem Applet verwendet es die API, die JDBC direkt aufruft, um auf die Datenbank zuzugreifen, die sehr effizient ist. Vermeiden Sie Leistungsprobleme, die durch Hibernate -Abfragen und in den Speicher geladen werden und dann Operationen ausführen.
2: Verwenden Sie gespeicherte Verfahren. Diese Methode wird jedoch aufgrund der Bequemlichkeit der Portabilität und der Programmbereitstellung nicht empfohlen. (Das Beispiel ist eine Aktualisierungsoperation)
Wenn die zugrunde liegende Datenbank (z. B. Oracle) gespeicherte Prozeduren unterstützt, können auch Stapel -Updates durch gespeicherte Prozeduren durchgeführt werden. Speichernde Prozeduren werden schneller in der Datenbank ausgeführt. In der Oracle -Datenbank kann eine gespeicherte Prozedur mit dem Namen batchUpDateCustomer () definiert werden. Der Code lautet wie folgt:
Die Codekopie lautet wie folgt: Erstellen oder Ersetzen von Prozeduren batchUpDateCustomer (P_AGE in der Anzahl) als Aktualisierung von Kunden festlegen Alter = Alter+1 Wenn Alter> p_age; enden;
Die obige gespeicherte Prozedur hat einen Parameter p_age, der das Alter des Clients darstellt. Die Anwendung kann die gespeicherte Prozedur auf folgende Weise aufrufen:
tx = session.beginTransaction (); connection con = session.connection (); String procedure = "{call batchUpDateCustomer (?)}"; CALLABLESTATEMENT CSTMT = CON.PREPARECALL (Prozedur); CSTMT.Setint (1, 0); // Setzen Sie den Altersparameter auf 0cstmt.executeUpdate (); tx.commit ();Wie aus dem obigen Programm hervorgeht, muss die Anwendung auch die Hibernate -API umgehen und gespeicherte Verfahren direkt über die JDBC -API aufrufen.
3: Verwenden Sie die Hibernate -API, um eine regelmäßige Chargenverarbeitung durchzuführen. Es kann Änderungen geben, und die Änderung wird sich ändern. Wenn wir einen bestimmten Betrag finden, können wir die Daten nach Abschluss der Operation Session.flush () rechtzeitig löschen. Session.evict (xx -Objektsatz); Dies kann auch einige Leistungsverluste sparen. Diese "bestimmte Menge" muss eine quantitative Referenz sein, die auf tatsächlichen Bedingungen basiert ...
(Das Beispiel ist ein Speichervorgang)
Die Geschäftslogik lautet: Wir möchten 10 0000 Datenstücke in die Datenbank einfügen
tx = session.
Dadurch hält das System in einem stabilen Bereich ...
Während des Projektentwicklungsprozesses müssen wir aufgrund von Projektanforderungen häufig große Datenmengen in die Datenbank einfügen. Es gibt Zehntausende, Zehntausende, zehn Millionen, sogar zehn Millionen von ihnen. Wenn Sie Hibernate zum Einfügen von Daten dieser Größenebene verwenden, kann eine Ausnahme auftreten. Die übliche Ausnahme ist Out ofMemoryError (Speicherüberlauf -Ausnahme).
Lassen Sie uns zunächst kurz den Mechanismus des Hibernate -Insertionsbetriebs überprüfen. Hibernate muss seinen internen Cache beibehalten. Wenn wir den Einfügenvorgang ausführen, setzen wir alle Objekte für den Betrieb in unserem internen Cache für die Verwaltung ein.
Wenn es um den Cache von Hibernate geht, hat Hibernate Theorien mit internem Cache und sekundärem Cache. Da Hibernate für diese beiden Caches unterschiedliche Verwaltungsmechanismen hat, können wir seine Größe in Bezug auf den sekundären Cache konfigurieren, während für interne Caches Hibernate eine "Leinenstreaming" -Haltung annimmt und die Kapazität keine Begrenzung gibt. Jetzt wird der Kern des Problems gefunden. Wenn wir massive Daten einfügen, werden so viele Objekte in den internen Cache aufgenommen (der interne Cache wird im Speicher zwischengespeichert), sodass Ihr Systemspeicher Stück für Stück aufgefressen wird. Wenn das System endlich "gebraten" ist, ist es vernünftig.
Überlegen wir, wie Sie mit diesem Problem besser umgehen können? Einige Entwicklungsbedingungen müssen mit Hibernate behandelt werden, und natürlich sind einige Projekte flexibler und Sie können andere Methoden finden.
Hier empfehle ich zwei Methoden:
(1): Hibernate optimieren und die Methode der segmentierten Insertion verwenden, um den Cache rechtzeitig auf dem Programm zu löschen.
. Diese Methode hat die beste Leistung und die schnellste.
Für Methode 1 oben ist die Grundidee: Hibernate optimieren und den Parameter hibernate.jdbc.batch_size in der Konfigurationsdatei festlegen, um die Anzahl der SQL anzugeben, die jedes Mal übermittelt wurden. Das Programm verwendet die Methode, um den Cache in der Zeit in segmentierter Einfügung zu beseitigen (Sitzung implementiert asynchrones Schreibverhalten, mit dem Hibernate explizit Vorgänge schreiben kann), dh sie aus dem internen Cache rechtzeitig löschen, nachdem sie eine bestimmte Datenmenge eingefügt haben und den besetzten Speicher befreit.
Um den Parameter hibernate.jdbc.batch_size festzulegen, können Sie sich auf die folgende Konfiguration beziehen.
<Hibernate-Configuration> <Sitzungsfaktor>… <Eigenschaft Name = "hibernate.jdbc.batch_size"> 50 </property>… <Session-factory> <Hibernate-Configuration>
Der Grund für die Konfiguration des Parameters hibernate.jdbc.batch_size besteht darin, die Datenbank so wenig wie möglich zu lesen. Je größer der Wert des Parameters hibernate.jdbc.batch_size, desto weniger die Zeiten, in denen Sie die Datenbank lesen, und desto schneller die Geschwindigkeit. Aus der obigen Konfiguration ist zu erkennen, dass Hibernate wartet, bis das Programm 50 m² akkumuliert, bevor es in Stapeln eingereicht wird.
Der Autor glaubt auch, dass der Wert des Parameters hibernate.jdbc.batch_size möglicherweise nicht so groß wie möglich festgelegt wird, und er bleibt aus einer Perspektive zu erörtern. Dies erfordert die Berücksichtigung der tatsächlichen Situation und die Einstellung dieser Angemessenheit. Im Allgemeinen kann das Einstellen von 30 oder 50 den Anforderungen entsprechen.
In Bezug auf die Programmumsetzung
Session Session = hibernateUtil.currentSession (); transatcion tx = session.begintransaction (); für (int i = 0; i <10000; i ++) {student st = new student (); St.SetName ("feifei"); Session // mit der Datenbankdatensitzung synchron bleiben.clear (); // Alle Daten intern löschen und den besetzten Speicher rechtzeitig freigeben}} tx.commit (); ...Unter einer bestimmten Datenskala kann dieser Ansatz die Systemspeicherressourcen in einem relativ stabilen Bereich aufrechterhalten.
HINWEIS: Der zuvor erwähnte Cache der zweiten Ebene ist für mich erforderlich, um ihn hier zu erwähnen. Wenn der sekundäre Cache aktiviert ist, wird der Hibernate die entsprechenden Daten zum Sekundärcache für den sekundären Cache aufgeladen, wenn wir Vorgänge einfügen, aktualisieren und löschen. Es wird einen enormen Leistungsverlust geben, daher empfiehlt der Autor, Level -2 -Cache in der Stapelverarbeitung zu deaktivieren.
Für die Methode 2 wird die herkömmliche JDBC -Stapelverarbeitung verwendet und die JDBC -API wird verwendet, um sie zu verarbeiten.
Bitte beziehen Sie sich in der Java-Batch-Verarbeitung und der Self-Execution SQL.
Wenn Sie sich den obigen Code ansehen, haben Sie immer das Gefühl, dass etwas unangemessen ist? Ja, hast du es nicht bemerkt! Dies ist immer noch die traditionelle Programmierung von JDBC ohne Winterschlafgeschmack.
Der obige Code kann an Folgendes geändert werden:
Transaktion TX = Session.BeginTransaction (); // Hibernate Transaction Processing Connection Connection Conn = Session.Connection () verwenden; Vorbereitungsdaten STMT = CONN.PREPARESTATEMENT ("In t_student (Name) Werte (?)"); für (int j = 0; j ++; j <200) {für (int i = 0; i ++; j <50) {stmt.setString (1, "feifei");}} stmt.executeUpdate (); tx.commit (); // Verwenden Sie Hibernate Transaction -Verarbeitungsgrenze ...Diese Änderung wird einen Winterschlafgeschmack haben. Nach dem Testen verwendet der Autor die JDBC -API für die Batch -Verarbeitung, die fast zehnmal höher ist als die Verwendung der Hibernate -API. Dies ist zweifellos die dominierende Leistung von JDBC.
In der Batch -Update und Löschung von Hibernate2 findet Hibernate für Batch -Update -Vorgänge die Daten heraus, die den Anforderungen entsprechen und dann den Aktualisierungsvorgang durchführen. Gleiches gilt für die Stapeldeletion. Ermitteln Sie zuerst die Daten, die den Bedingungen erfüllen, und führen Sie dann den Löschvorgang durch.
Dies hat zwei Hauptnachteile:
(1): Nimmt viel Erinnerung an.
(2): Bei der Verarbeitung massiver Daten ist die Ausführung der Aktualisierungs-/Delete -Anweisung eine massive Menge, und eine Aktualisierungs-/Löschanweisung kann nur ein Objekt bedienen. Es ist denkbar, dass die Leistung der Datenbank niedrig ist, wenn sie häufig betrieben wird.
Nachdem Hibernate3 veröffentlicht wurde, wurde das Bulk Update/Delete für Batch -Update/Delete -Vorgänge eingeführt. Das Prinzip besteht darin, die Batch -Update/Löschen von Vorgängen durch eine HQL -Anweisung zu vervollständigen, die den Batch -Update/Löschen von JDBC sehr ähnlich ist. In Bezug auf die Leistung gibt es eine große Verbesserung gegenüber Batch -Updates/Löschen von Hibernate2.
Transaktion TX = Session.beGinSession (); String hql = "Student löschen"; query query = session.createquery (HQL); int size = query.executeUpdate (); tx.commit (); ...
Die Konsole gibt nur eine Löschanweisung Hibernate aus: Löschen von t_student. Die Ausführung der Anweisung ist geringer und die Leistung ist fast die gleiche Verwendung von JDBC. Es ist eine gute Möglichkeit, die Leistung zu verbessern. Um eine bessere Leistung zu erzielen, empfiehlt der Autor natürlich, dass Batch -Updates und Löschvorgänge noch JDBC verwenden. Die Methoden und Grundkenntnisse sind im Grunde die gleichen wie die oben genannte Stapel -Einfügungsmethode 2, sodass ich sie hier nicht redundant beschreiben werde.
Hier biete ich eine andere Methode an, die die Verbesserung der Leistung von der Datenbankseite in Betracht ziehen soll und gespeicherte Verfahren auf der Seite des Hibernate -Programms aufgerufen wird. Speichernde Prozeduren, die auf der Datenbankseite schneller ausgeführt werden. Als Beispiel wird der Referenzcode angegeben.
Erstellen Sie zunächst eine gespeicherte Prozedur mit dem Namen batchupdatestudent auf der Datenbankseite:
Erstellen oder ersetzen Sie die Produkte batchupdatestudent (a in Anzahl) Asbeginupdate Student Set Alter = Alter+1 Where Alter> a; enden;
Der Anrufcode lautet wie folgt:
Transaktion tx = session.beginSession (); Verbindung conn = session.Connection (); String pd = "… {call batchUpDatestudent (?)}"; CALLABLESTATEMENT CSTMT = CONN.PREPARECALL (PD); CSTMT.SETING (1, 20); // den Altersparameter auf 20TX.Commit () festlegen;Wenn Sie den obigen Code beobachten, wird auch die Hibernate -API umgeht und die JDBC -API verwendet, um gespeicherte Prozeduren aufzurufen, und verwendet die Transaktionsgrenzen von Hibernate. Gespeicherte Verfahren sind zweifellos eine gute Möglichkeit, die Batch -Verarbeitungsleistung zu verbessern. Sie laufen direkt mit der Datenbankseite und übertragen in gewissem Maße den Druck der Stapelverarbeitung in die Datenbank.
PostScript
In diesem Artikel werden die Batch -Verarbeitungsvorgänge von Hibernate erläutert, und der Ausgangspunkt besteht darin, die Leistung zu verbessern, und er bietet nur einen kleinen Aspekt bei der Verbesserung der Leistung.
Unabhängig davon, welche Methode angewendet wird, muss sie auf der Grundlage der tatsächlichen Bedingungen berücksichtigt werden. Benutzer ein effizientes und stabiles System zu bieten, das ihren Anforderungen entspricht, hat oberste Priorität.
Ich hoffe, dieser Artikel wird für die Hibernate -Programmierung aller hilfreich sein.