24 Stimmen

Batch-Einfügungen mit JPA/EJB3

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

22voto

Pascal Thivent Punkte 548176

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

5voto

Loki Punkte 28114

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.

5voto

Tho Punkte 19990

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

1voto

JARC Punkte 5168

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

1voto

shudong Punkte 86

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X