Hibernate EntityManagerのフィールド関連について

id:koichik:20060122#1137951021


Hibernate のAbstractEntityManagerのソースを自分なりに追っていたのですが、beta6から、javax.persistence.FlushModeTypeのフィールドを持つようになりました。PFDでFlushModeTypeからNEVERが削除されたことへの対応のようです。
このフィールドを使っているメソッドは3箇所です。まずはadjustFlushMode()。これはあらゆるEntityManagerのメソッドを実行する前に、FlushModeTypeをチェックするメソッドのようです。トランザクションが有効で、SessionのFlushModeがNEVERのときには、フィールドのFlushModeType(デフォルトはAUTO)をSessionにセットします。また、トランザクションが無効でSessionのFlushModeがNEVERでないときには、SessionのFlushModeをNEVERに変更します。「トランザクションが有効で、SessionのFlushModeがNEVERのとき」にフィールドの情報が利用されてしまいますが、トランザクションが有効なときにSessionがNEVERになるのは、Hibernateをそういう定義にするか、同一トランザクション上でSessionを呼び出してNEVERをセットしない限り発生しないと思いますので、このメソッドは問題ではないように思われます。
次にsetFlushMode()。これは引数で受け取ったFlushModeTypeをフィールドに保持した後、引数の値を元にSessionのFlushModeをsetしてます。ここも問題ないように思われます。
最後にgetFlushMode()。これはSessionからFlushModeを取得して、その値を元にフィールドのFlushModeTypeを変更し、最後にフィールドの値を戻り値として戻しています。
このメソッドの最後の行の「return flushMode」が問題ではないかと思いました。EntityManagerがsingletonだった場合、意図しないFlushModeTypeが返される可能性があると思います。・・・ただ、問題になるのはgetFlushModeの結果によって処理を変えたりする場合ですが・・・このメソッドの値をあてにせずにsetFlushModeでフラッシュモードを制御するようにすれば、特に問題はないのかな?
AbstractEntityManagerはEntityTransaction実装オブジェクトの値もフィールドに持ちますが、このフィールドはgetTransaction()メソッドを呼ばない限り使われません。PFDによると

/**
* Return the resource-level transaction object.
* The EntityTransaction instance may be used serially to
* begin and commit multiple transactions.
* @return EntityTransaction instance
* @throws IllegalStateException if invoked on a JTA
* EntityManager or an EntityManager that has been closed.
*/
public EntityTransaction getTransaction();

となってますので、JTAを使う環境であればこのメソッドは使えない筈。今のHibernateの実装では、一旦例外を出すように書いた後コメントアウトにされてますね。おそらく、正式版が出るまでには、JTA環境では使えなくなるのではないかと思われます。だからこのフィールドも問題ないかな?
PFDを読んだかんじでは(とはいっても自分は英語力が弱いのでいろいろ漏らしてる可能性が高いですが)、EntityManagerはPersistenceContextに紐づくオブジェクトとして定義されており、PersistenceContextがTransactionScopeだった場合、結果としてトランザクションに紐づくように見受けられます。ただし、トランザクションが終了したら使えないわけではないみたいで・・・PFDの「5.1 Persistence Contexts」ではこう書かれてます。

This propagation of persistence context by the Java EE container avoids the need for the application to pass references to Entity-Manager instances from one component to another.

ってことは、あるトランザクション固有の情報をEntityManagerが持ってる前提では無い気がするのですが・・・
すみません、いろいろ書いてしまいましたが、getTransaction()を使わず(これはJTA環境なら仕様として正しい筈)getFlushMode()の値に依存しない(これは仕様的にはまずいかも?)ようにすれば、singletonでも大丈夫なのかな? このgetFlusMode()のところが自分的には引っかかってます。ただ、これがprototypeになってしまったら、これを使うあらゆるコンポーネントがprototypeになってしまうわけで・・・
PFDを読んでると、ところどころで「JTAをサポートするJava SEベースのコンテナ環境」みたいな表現が出てくるので、DIコンテナ(標準でJTA環境を提供してるのはS2しか無い気がしますが)のことも意識してる気はするのですが・・・今回のHibernate実装側の変更は、個人的にはありがたくない内容でした。