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

Reply via email to