Stateful EJB with extended persistence context to handle user session
I'm using a CDI session scoped bean to hold user related information (His user entity bean, credential, etc). I have a save method for everytime a user changes his info (like email, password, etc). However, I could have a stateful session bean with extended persistence context to do so. If I do that, his user entity will become managed during his session and changes to his email etc would be synchronized without recreating persistence contexts etc. Is this a good idea? Should I have an extended persistence context open for so long? This also locks changes to the user for external beans right开发者_Go百科? What if I have an administrator trying to make changes to this user (it could happen).
There are a couple of side-effects you need to beware of.
The first thing is that the extended persistence context you use to hold this user entity should not be used for much else, as it automatically caches everything being touched (the L1 cache).
If you need to use this continuously attached user entity in some other operation dealing with some other persistence context, you need to fetch a fresh instance instead of using the instance in session scope.
The locking thing does not happen automatically. Normally, different persistence contexts can also modify the same entity. Typically the last one to do any writes will 'win'. If you want to prevent this, you can take advantage of the normal locking operations in JPA. For this case, optimistic locks are probably best suited.
I'm curious though how well this will work in practice. It's surely a novel idea. From reading many blog posts, articles, books and discussions with many developers, I get the feeling that the extended persistence context is fairly little known thing and not that much best practices have been created for it.
The fact that Stateful session beans can now be scoped via CDI (and thus automatically destroyed when e.g. the HTTP session is destroyed) makes the entire concept much more viable. But CDI too is relatively new, and a lot of people still have to discover how to best use it.
I'm using an extended persistence context in various Java EE 6 projects, this is the scenario:
- a "facade" (sfsb), injecting service(s)
- a "service" injects the EM
- a "dbproducer" produces the EM into the conversation scope of the facade
- the facade has all transactions disabled by default (eg
loadEntity()
has no transaction) - certain facade methods explicitly enable transaction (eg.
saveEntity()
has a transation)
What happens is that:
- A entity is loaded and stays managed for the complete duration of the conversation (perfectly cached by the persistence context, which - in the absence of a transaction - will not flush).
- If (and only if, for the sake of the example) a entity is saved, a transaction will be explicitly opened, and the persistence context flushes into the db if the transaction succeeded.
- In case that any other edits did take place (eg by the administrator), a
OptimisticLockingException
will be thrown, and be handled by the application
This works like a charme, and feels pretty elegant too :-)
One word of warning - as the EM isn't serializable - *if * you are working in a cluster, you'll forced to use a sticky session strategy, because those EJBs can't be moved from one server to the other.
You might also want to think about some way to have the EM joining an existing transaction (this can easily happen if you have more than one service call per request). If you are on a non-Seam 3 stack, a proxied EM is an option, if you are on Seam 3, use @Unwraps
(Solder) instead of @Produces
and check if there's a transaction to be joined.
精彩评论