EntityManage はスレッドセーフではない
おそらく FA です.
id:taedium さん,id:da-yoshi さん,ご協力ありがとうございました.
Hibernate EntityManager のドキュメントには次のようにはっきりと書いてありました.
AnEntityManager
is an inexpensive, non-threadsafe object that should be used once, for a single business process, a single unit of work, and then discarded.
Hibernate EntityManager が堂々とスレッドセーフじゃないと言い切ってるってことは,Persistence API では EntityManager
をスレッドセーフにすることを義務づけてはいないということでしょう.
id:taedium さんが引用してくれているように,実装側で好きなようにしていいらしい.
実際,仕様書には "thread" という用語は一度も使われていません.恐るべし.
っていうか,「EntityManager
はスレッドセーフでなくてもいい」「EntityManager
がスレッドセーフだと期待してはいけない」とか書いておいて欲しいなぁ.
そんなわけで (どんなわけで?),id:da-yoshi さんが挙げておられる getFlushMode()
などがスレッドセーフでない Hibernate EntityManager 3.1beta6 の実装はまるっと問題なしということになりますね.
EntityManager
はスレッドセーフではないので,singleton
にすることはできません.
また,EntityManager
を DI されるコンポーネント (Dao) なんかも singleton
にしてはいけません.
という書き方はあまり正確じゃないですね.
singleton
でも prototype
でも何でもいいけど,複数のスレッドから同時に同じ EntityManager
を使ってはいけません.再入禁止.
もっとも,DB アクセスを伴う EntityManager
を同期して使うことはあり得ないので,結局 singleton
禁止.
で,アプリケーションコンポーネントはどうするか.
現実的な手段は昨日書いたように
- Dao もサービスもみーんな
prototype
にする. EntityManager
ではなく,EntityManagerFactory
を DI してもらう.
ってところでしょう.
他にはスレッドセーフな EntityManager
のプロキシを提供するっていう手もなくはないけど...
PrototypeDelegateInterceptor
使えば簡単そうだけど...
普通なら間違ってる使い方が正しく動いちゃうのはかなりいやーんなのでボツ.
で,EJB3 的には前者 (みーんな prototype
) なんだろうなぁ.
そもそも EntityManager
なんかを DI してもらえるってことはそいつは EJB なわけで,そして EJB はなんたって再入不可なので,そもそもが singleton
のような使い方はあり得ないわけで.
でもでも,実は Servlet にも @PersistenceContext
なんかを書けるとかいう話があって (Servlet 2.5 Maintenance Review August 11, 2005 にはそんな記述無いけど),そして Servlet は EJB と違ってデフォルトでは再入可なわけで,ってことはどうするかっていうと後者 (EntityManagerFactory
を使う) らしい.以下参照.
http://weblogs.java.net/blog/ss141213/
ってことは,EntityManagerFactory
はスレッドセーフだと決めつけていいのだろうか?
Hibernate EntityManager の実装はスレッドセーフだと明記されているけど,Persistence API 仕様では義務づけられているようには見えないわけですが.
まぁいいや.
ともあれ (JW),この辺は Dao やサービスを EJB3 として作りたい (他の EJB3 コンテナでも動かしたい) のか,EJB3 なんてどうでもいいのかで違ってきそうですね.
EJB3 として作るなら最初から singleton
はあり得ないから悩むことは何もなくて,Dao もサービスもみーんな Session Bean.結果的にみーんな prototype
になるので EntityManager
を DI してもらえばそれでよし.
EJB3 どーでもよければ prototype
にして EntityManager
を DI してもらうのも在^hありだし,singleton
にして EntityManagerFactory
を DI してもらうのも在^hあり.
いずれにせよ,S2Hibernate-JPA としては EntityManagerFactory
を singleton
,EntityManager
を prototype
で提供するので,お好きなようにどうぞという感じ.