Bietet das JPA/EJB3-Framework eine Standardmethode für Batch-Insert-Operationen? Wir verwenden Hibernate für Persistenz-Framework, also kann ich auf Hibernate Session zurückgreifen und die Kombination session.save()/session.flush() verwenden, um Batch Insert zu erreichen. Aber würde gerne wissen, ob EJB3 haben eine Unterstützung für diese...
Antworten
Zu viele Anzeigen?Weder JPA noch Hibernate bieten besondere Unterstützung für Batch-Inserts und das Idiom für Batch-Inserts mit JPA wäre das gleiche wie mit Hibernate:
EntityManager em = ...;
EntityTransaction tx = em.getTransaction();
tx.begin();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
em.persist(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size
//flush a batch of inserts and release memory:
em.flush();
em.clear();
}
}
tx.commit();
session.close();
Die Verwendung der proprietären API von Hibernate bietet in diesem Fall IMO keinen Vorteil.
Referenzen
- JPA 1.0 Spezifikation
- Abschnitt 4.10 "Massenaktualisierungs- und Löschvorgänge"
- Hibernate Core Referenzhandbuch
Speziell für den Winterschlaf ist die gesamte Kapitel 13 des Kernhandbuchs die Methoden erklären.
Aber Sie sagen, dass Sie die EJB-Methode durch Hibernate, so dass die Entity-Manager-Dokumentation hat auch ein Kapitel über diese ici . Ich schlage vor, dass Sie beides lesen (den Kern und den Entity Manager).
In EJB geht es einfach um die Verwendung von EJB-QL (mit einigen Einschränkungen). Hibernate bietet jedoch mehr Mechanismen, wenn Sie mehr Flexibilität benötigen.
Bei mittleren Datensätzen können Sie diesen Weg nutzen:
em.getTransaction().begin();
for (int i = 1; i <= 100000; i++) {
Point point = new Point(i, i);
em.persist(point);
if ((i % 10000) == 0) {
em.flush();
em.clear();
}
}
em.getTransaction().commit();
Bei einer großen Anzahl von Datensätzen sollten Sie diese Aufgabe jedoch in mehreren Transaktionen durchführen:
em.getTransaction().begin();
for (int i = 1; i <= 1000000; i++) {
Point point = new Point(i, i);
em.persist(point);
if ((i % 10000) == 0) {
em.getTransaction().commit();
em.clear();
em.getTransaction().begin();
}
}
em.getTransaction().commit();
Ref: JPA-Stapelspeicher
Ja, Sie können zu Ihrer JPA-Implementierung zurückkehren, wenn Sie die von Ihnen definierte Kontrolle haben möchten.
JPA 1.0 bietet viel EL-HQL, aber nur wenig Unterstützung für Criteria API, was jedoch in Version 2.0 behoben wurde.
Session session = (Session) entityManager.getDelegate();
session.setFlushMode(FlushMode.MANUAL);
Pascal
In Ihrem Beispiel zum Einfügen von 100000 Datensätzen wird dies innerhalb einer einzigen Transaktion durchgeführt, da das Commit() erst am Ende aufgerufen wird. Stellt das eine große Belastung für die Datenbank dar? Außerdem werden die Kosten im Falle eines Rollbacks zu hoch sein.
Ist der folgende Ansatz besser?
EntityManager em = ...;
for ( int i=0; i<100000; i++ ) {
if(!em.getTransaction().isActive()) {
em.getTransaction().begin();
}
Customer customer = new Customer(.....);
em.persist(customer);
if ((i+1) % 20 == 0 ) { //20, same as the JDBC batch size
//flush and commit of inserts and release memory:
em.getTransaction().commit();
em.clear();
}
}
session.close();