web-dev-qa-db-ja.com

JPA / EJB3を使用したバッチ挿入

JPA/EJB3フレームワークは、バッチ挿入操作を行うための標準的な方法を提供しますか?永続性フレームワークにはHibernateを使用しているため、Hibernate Sessionにフォールバックし、session.save()/ session.flush()の組み合わせを使用してバッチ挿入を実現できます。しかし、EJB3がこれをサポートしているかどうか知りたいです...

21
Raja

JPAもHibernateもバッチ挿入を特別にサポートしておらず、JPAを使用したバッチ挿入のイディオムは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();

この場合、Hibernate独自のAPIを使用しても、IMOの利点はありません。

参考文献

  • JPA1.0仕様
    • セクション4.10「一括更新および削除操作」
  • HibernateCoreリファレンスガイド
21
Pascal Thivent

特にHibernateの場合、全体 コアマニュアルの第13章 メソッドを説明します。

しかし、Hibernateを介したEJBメソッドが必要だと言っているので、エンティティマネージャーのドキュメントにもその章があります ここ 。両方(コアとエンティティマネージャー)を読むことをお勧めします。

EJBでは、EJB-QLを使用するだけです(いくつかの制限があります)。より柔軟性が必要な場合でも、Hibernateはより多くのメカニズムを提供します。

5
Loki

中程度のレコード数では、次のように使用できます。

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

ただし、レコード数が多い場合は、このタスクを複数のトランザクションで実行する必要があります。

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

参照: JPAバッチストア

4
Tho

パスカル

100000レコードを挿入する例では、commit()は最後にのみ呼び出されるため、単一のトランザクション内で実行されます。データベースに大きなプレッシャーをかけますか?さらに、ロールバックが発生した場合、コストが高すぎます。

次のアプローチの方が良いでしょうか?

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

はい、定義したコントロールを取得するために、必要に応じてJPA実装にロールバックできます。

JPA 1.0はEL-HQLが豊富ですが、Criteria APIのサポートは少ないですが、これは2.0で対処されています。

Session session = (Session) entityManager.getDelegate();
session.setFlushMode(FlushMode.MANUAL);
1
JARC