2017-02-21 7 views
0

汚れたオブジェクトを含まないエンティティ・マネージャからトランザクションをコミットするとどうなりますか? COMMITコマンドがDBに送信されないことはありますか?アンラップされた接続によってJPAコミットの変更が行われる

私はいくつかのテストケースが今や失敗していて、合理的な理由がないままでした。いくつかの調査の後、ここで私がここで確認したい理論があります。

私は小さなテストフレームワークを持っており、各テストのDB上のデータを準備しています。固定具は、JPA(休止状態)を使用してDBにオブジェクトを格納するような方法を使用します。したがって

public <R> R doInTransaction(final Function<EntityManager, R> whatToDo) { 
    final EntityManager em = emf.createEntityManager(); 
    final R result; 
    try { 
     try { 
     em.getTransaction().begin(); 
     result = whatToDo.apply(em); 
     em.getTransaction().commit(); 
     } finally { 
     if (em.getTransaction().isActive()) { 
      em.getTransaction().rollback(); 
     } 
     } 
    } finally { 
     em.close(); 
    } 
    return result; 
    } 

を、固定具は、オブジェクトが永続化さwhatToDo関数を渡し、このメソッドを呼び出し、メソッドは、渡された関数の周りにトランザクションをラップ。失敗したテストケースでは、ストアドプロシージャを使用するレガシーコードに依存するフィクスチャを使用し、JDBCを介してオブジェクトを直接格納しています。 e。によって管理されるいかなるJPA済オブジェクトが存在しないように、私の理論は、JPAは、このような状況ですぐにコミットされていないということです

em.unwrap(Session.class).doWork(connection -> { 
    // stored procedures are called here directly over JDBC 
}); 

:代わりにem.persist()を使用して、私はストアドプロシージャを呼び出すために渡された関数で次のように使用しますEntityManager。その結果、実際のコミットは後でのみ発生します。 e。私のテストの主張の後に、テストは失敗します。それは可能性が?

EntityManagerから接続を「アンラッピングする」ときのHibernateのトランザクション動作は何ですか?

em.getTransaction().commit()の前にem.flush()を追加しましたが、これは役に立ったようですが、これが問題を解決するとはまだ100%自信がありません。誰かが確認できますか?

+0

永続性ハンドラを混合してマッチングするときは注意が必要です。 Hibernateは、何が汚いのか、何がないのかのキャッシュを維持します。休止状態以外のものを更新している場合、キャッシュされたエンティティのバージョンがまだ有効であると思うので、休止状態がdbと同期しなくなり、更新が破棄される可能性があります。私はこのような問題を数年前に実行していましたが、正しく覚えていれば、動作を阻止するために休止状態でキャッシュを無効にしました。 – Stephan

+0

私はHibernateでキャッシングの不思議な世界に入りたくないのです。:) 'em.flush()がここで仕事をするなら、これで十分です。 – Alex

+0

テスト環境にいる場合、em.flush()を試してみることができます。並んでいる人数が並外れていると予想されない場合は、休止状態でキャッシュを無効にして、データベース内のキャッシュが大量の作業を処理できるようにする必要があります。これは別のことですが、dbのデフォルトのキャッシングは、hibernateのデフォルトキャッシングを妨げる可能性があります。引き続き問題が発生する場合は、休止状態のキャッシュをオフにすることを強くお勧めします。 – Stephan

答えて

0

接続のアンラッピングに関係なく動作は同じです。 JTAを使用していない場合は、JDBCが提供する基本トランザクション、つまりローカルトランザクションです。

接続をアンラップしてJDBCを直接処理すると、このセッション/エンティティマネージャによって最初に取得された接続と同じ接続が得られます。だから同じ効果です。

+0

接続をアンラップしてJDBCを直接処理すると、同じ接続が得られます。そのため、em.getTransaction()。commit()はJDBCで直接行われた変更をコミットすることを期待していました。しかし、これは明らかに汚れたオブジェクトがない場合、必ずしもそうであるとは限りません。したがって、私の理論は有効ですか? 'em.flush()'はコミットを強制しますか?私はJDBCから直接コミットするのではなく、 'doInTransaction()'の中で何が行われても、DBの観点からは1つのトランザクションであることを好みます。 – Alex

+0

JPAエンティティに更新が加えられた場合は、ダーティとマークされます。 Hibernateでは、エンティティへの変更はイベントに変換され、フラッシュ時にのみイベントがSQLに変換されてJDBCに渡されます。変更がなければ(ダーティなエンティティはない)、パイプラインにはSQLが存在しないので、コミットまたはコミットは同じ効果を持ちます。 – raminr

関連する問題