web-dev-qa-db-ja.com

Hibernate commit()およびflush()

私はたくさんのグーグルでorg.hibernate.Transaction.commit()org.hibernate.Session.flush()についてよく読んで、それぞれの方法の目的を知っていましたが、まだ質問があります。

org.hibernate.Session.flush()メソッドを手動で呼び出すことをお勧めしますか? org.hibernate.Sessionドキュメントで述べたように、

トランザクションをコミットしてセッションを閉じる前に、作業ユニットの最後に呼び出す必要があります(フラッシュモードに応じて、Transaction.commit()はこのメソッドを呼び出します)。

org.hibernate.Session.flush()が自動的に呼び出す場合、org.hibernate.Transaction.commit()を手動で呼び出す目的を説明してもらえますか?

ありがとう!

64
bsiamionau

Hibernate Manualでは、この例を見ることができます

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();


for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

Flushメソッドを呼び出さないと、一次キャッシュはOutOfMemoryExceptionをスローします

また、フラッシュに関するこの投稿を見ることができます

84
Aleksei Bulgak

flush()は、データベースをメモリに保持されているオブジェクトの現在の状態と同期しますが、トランザクションをコミットしません。したがって、flush()が呼び出された後に例外が発生した場合、トランザクションはロールバックされます。 flush()を使用して一度に大きなデータをコミットする代わりに、commit()を使用してデータベースを小さなデータチャンクと同期すると、Out Of Memory Exceptionが発生するリスクに直面します。

commit()は、データベースに保存されたデータを永続化します。 commit()が成功すると、トランザクションをロールバックする方法はありません。

58
Anand Kulkarni

明示的にフラッシュする一般的なケースの1つは、新しい永続エンティティを作成し、生成されて割り当てられた人工主キーを使用して、後で同じトランザクションで使用できるようにする場合です。その場合、flushを呼び出すと、エンティティにIDが与えられます。

もう1つのケースは、1次キャッシュに多くのものがあり、定期的に(キャッシュで使用されるメモリ量を減らすために)消去したいが、それでもすべてをまとめてコミットしたい場合です。 。これは、 Alekseiの答え カバー(私から+1)の場合です。

47
Nathan Hughes

flush();フラッシュとは、メモリに保持されている永続可能な状態と基になる永続ストアを同期するプロセスです。実行中のトランザクションでテーブルに更新または挿入しますが、それらの変更をコミットしない場合があります。

バッチ処理でフラッシュする必要があります。そうしないと、OutOfMemoryException。

Commit(); Commitはデータベースをコミットします。永続化されたオブジェクトがあり、その値を変更すると、ダーティになり、Hibernateはこれらの変更を永続化レイヤーにフラッシュする必要があります。コミットしますが、作業単位も終了します。transaction.commit()

12
Ashu

通常、必要でない限り、明示的にflushを呼び出すことはお勧めしません。 Hibernateは通常、トランザクションの終了時にFlushを自動呼び出しし、それを動作させる必要があります。現在、2番目のタスクが最初のPersistenceタスクの結果に依存し、両方が同じトランザクション内にある場合、明示的にflushを呼び出す必要がある場合があります。

たとえば、新しいエンティティを永続化し、そのエンティティのIDを使用して同じトランザクション内で他のタスクを実行する必要がある場合があります。その場合、最初にエンティティを明示的にフラッシュする必要があります。

@Transactional
void someServiceMethod(Entity entity){
    em.persist(entity); 
    em.flush() //need to explicitly flush in order to use id in next statement
    doSomeThingElse(entity.getId());    
}

また、明示的にフラッシュしてもデータベースのコミットは発生せず、データベースのコミットはトランザクションの最後でのみ行われるため、フラッシュの呼び出し後にランタイムエラーが発生した場合、変更は引き続きロールバックされることに注意してください。

5
adn.911

デフォルトでは、フラッシュモードはAUTOです。つまり、「クエリが古い状態を返さないようにするために、クエリ実行前にセッションがフラッシュされることがあります」が、ほとんどの場合、変更をコミットするとセッションがフラッシュされます。 FlushMode = MANUALを使用する場合、または何らかの最適化を行う場合は、flushメソッドの手動呼び出しが便利です。しかし、私はこれをやったことがないので、実際的なアドバイスをすることはできません。

3
dimas

session.flush()は、データベースにデータを順番に挿入する同期メソッドです。このメソッドを使用すると、データはデータベースに保存されませんが、キャッシュに保存されます。途中で例外が発生した場合は処理できます。ただし、commit()はデータベースにデータを保存します。より多くのデータを保存している場合は、JDBCプログラムのSave pointトピックのように、メモリ例外が発生する可能性があります。

2
Gautam Prusty