JPA/EJB3フレームワークは、バッチ挿入操作を行うための標準的な方法を提供しますか?永続性フレームワークにはHibernateを使用しているため、Hibernate Sessionにフォールバックし、session.save()/ session.flush()の組み合わせを使用してバッチ挿入を実現できます。しかし、EJB3がこれをサポートしているかどうか知りたいです...
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の利点はありません。
特にHibernateの場合、全体 コアマニュアルの第13章 メソッドを説明します。
しかし、Hibernateを介したEJBメソッドが必要だと言っているので、エンティティマネージャーのドキュメントにもその章があります ここ 。両方(コアとエンティティマネージャー)を読むことをお勧めします。
EJBでは、EJB-QLを使用するだけです(いくつかの制限があります)。より柔軟性が必要な場合でも、Hibernateはより多くのメカニズムを提供します。
中程度のレコード数では、次のように使用できます。
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バッチストア
パスカル
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();
はい、定義したコントロールを取得するために、必要に応じてJPA実装にロールバックできます。
JPA 1.0はEL-HQLが豊富ですが、Criteria APIのサポートは少ないですが、これは2.0で対処されています。
Session session = (Session) entityManager.getDelegate();
session.setFlushMode(FlushMode.MANUAL);