Given: simple JSF webapp (no Seam), having JSF beans calling few EJB's which in turn load and persist JPA entities. What I want to is to use @Singleton
annotation for ejb's and inject EntityManager
instead of EntityManagerFactory
:
@Singleton
public class MyEJB {
@PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
protected EntityManager em; // not EntityManagerFactory
}
Spec says that @Singleton
is thread-safe, supports concurrency and transaction attributes which (from my pov) makes it safe for calling from JSF beans. I expect also performance benefits because of EntityManager
not being recreated for each call and it's internal caching abilities.
My main concern here is create/update operations on JPA entities in the situation when I have several singletons and, as a result, the same cou开发者_开发问答nt of long-living EntityManagers.
- What happens if one singleton updates an JPA instance and how these changes are populated to other singletons?
- As I'm not able to close entity manager, do I need to flush it upon each entity update?
- Would it be better if these few singletons will share the same entity manager?
- I saw only few examples of such design. Why? Are there any serious drawbacks?
Many thanks in advance!
I expect also performance benefits because of EntityManager not being recreated for each call and it's internal caching abilities.
You might save some memory using singletons, but using it everywhere in your app could make it actually slower, because as there's only one EJB to serve all the concurrent requests by various users of your app, the container locks access to the EJB and when it's busy serving a request it cannot be serving another request. However this can be alleviated to some degree using lock types (i.e. @Lock(WRITE)
and @Lock(READ)
).
Singletons are useful for times when you want to execute a piece of code periodically using EJB timers, or to update a cache periodically, etc.
What happens if one singleton updates an JPA instance and how these changes are populated to other singletons?
Shouldn't be any different to the way non-singleton EJBs behave.
As I'm not able to close entity manager, do I need to flush it upon each entity update?
If you use CMT, no. At the end of each transaction everything will be flushed automatically.
Would it be better if these few singletons will share the same entity manager?
Looks like premature optimization to me. Just let the container inject the EM for you.
I saw only few examples of such design. Why? Are there any serious drawbacks?
Already explained.
There is one thing I want to mention regarding changing LockType of Singleton EJBs. While in general it sounds like a good idea, you should remember that resources such as EntityManger are NOT thread-safe, so appropriate concurrent access control should be provided. You can annotate methods that access non-thread-safe resources with @Lock(WRITE), but if almost all interface methods of your Singleton EJB access such resources, you will have almost the same situation as with fully write locked one. Alternative is to use Bean Concurrency Management with manual fine-grained synchronization, but it's also questionable decision.
Because of this in general I prefer Stateless EJBs over Singleton and use latter in specific cases.
精彩评论