Currently in jpa-container-context we wrap the EntityManager to ensure
we provide it in a thread safe way.
This is to emulate a usage pattern like in JEE where a pool of
EntityBeans are kept and the container guarantees that no two threads
access the same bean at the same time. I think this approach is
difficult to get right and also quite complicated to implement. It is
also conceptually bad as the EntityManager interface never was designed
to be used in a thread safe way.
So I wonder if we could use a different approach on the client side to
make this easier.
1. So one approach would be to use Java 8 lambdas to make the
entitymanager usage thread safe and transactional. It could look like this:
public void update(Task task ) {
peristenceManager.transactional(Required, em -> em.persist(task));
}
persistenceManager would be initialized once with the
EntityManagerFactory and the TransactionManager.
The advantage of this approach is that we do not need any wrapping at
all. We can simply create the EntityManager at the start of the
"transactional" method and close it in the end. We can also do the
transaction handling there. We also need no interceptors. So we do not
need to proxy the bean class.
The downside is that it is a little bit more verbose than annotation
based transactions and that it requires Java 8.
2. Another approach would be to store the EntityManager visibly in a
ThreadLocal in the client code:
@Singleton
@Transactional
public class TaskServiceImpl implements TaskService {
ThreadLocal<EntityManager> localEm;
public void updateTask(Task task) {
emLocal.get().persist(task);
}
}
The advantage here is that it does not need Java 8 and is a bit less
verbose than 1. Compared to our current solution the advantage would be
that we need no special
wrapping of the EntityManager. Before the call to updateTask we use an
interceptor to make sure the transaction is set up correctly and we
create the EntityManager for the thread. After the call we close the
EntityManager and handle the eventual commit or rollback.
The downside here is that it still needs an interceptor for transaction
handling and to make sure localEm contains a valid EntityManager for the
current Thread.
Solution 2 could also be introduced without creating additional
blueprint elements. We could simply detect that we inject into a
ThreadLocal and act accordingly.
So WDYT?
Christian
--
Christian Schneider
http://www.liquid-reality.de
Open Source Architect
http://www.talend.com