When the bean is created we would initialize the variable with:
localEm = new ThreadLocal<EntityManager>();
We already have an interceptor that runs around transactional methods.
Before the method call we could do:
EntityManager em = emf.createEntityManager();
localEm.set(em);
and after:
EnityManager em = localEm.get();
em.close();
localEm.remove();
This is of course largely simplified as it does not do error handling,
transaction handling, ...
but I think it would be easy to adjust that.
Probably we also need to keep the EntityManager and Transaction alive if
there are cascaded transactional calls.
Honestly I am not fully sure how much better my solution would be
compared to a simple wrapper that does the same internally.
Basically my main concern with the current wrapper is that it does a lot
more than just map each call to the EntityManager to the thread local
one. I wonder if it could be simplified a lot.
I am also not sure if we really need jpa-container-context or if we
could simply do the work inside the jpa-blueprint module.
Christian
Am 06.11.2014 14:07, schrieb Giuseppe Gerla:
Thanks Christian
now it's clear the problem and why we cannot use the EMF solution....
So let me come back on your second solution. I have some doubt about the
EntityManager creation.
Your code posted is only a part of solution. Can you complete it adding
the initialValue of ThreadLocal implementation?
Regards
Giuseppe
2014-11-06 13:39 GMT+01:00 Christian Schneider <ch...@die-schneider.net>:
Of course using the EntityManagerFactory is a possible and working way.
The problem is that it creates a lot of boilerplate code.
// This is how persist looks in JEE container managed persistence
public void updateTask(Task task) {
em.persist(task);
}
// This is halfway correct handling of transactions and em lifecycle
for plain java
public void updateTaskEmf(Task task) {
userTransaction.begin();
EntityManager em = emf.createEntityManager();
try {
em.persist(task);
userTransaction.commit();
} catch (RuntimeException e) {
userTransaction.rollback();
throw e;
} finally {
em.close();
}
}
As you see you need a lot of code around your business functionality to
handle EntityManager lifecycle and transactions. It becomes even more
complex if you
assume cascaded transactions where you have one transacted method that
calls other transacted methods. There you also want the EntityManager to
life throughout the cascaded transaction so you can do different changes to
persistent entities in the same em session before you finally commit.
So this is the reason why JEE does container managed persistence and also
the reason why we wrap the EntityManager in aries.
I proposed ThreadLocal to make it more obvious that EntityManager is not
thread safe and each thread will use its own instance. We do a similar
thing inside the wrapped EntityManager that jpa-container-context creates
but I think it is not good to hide that fact too much.
This is how we currently wrap the EntityManager:
https://github.com/apache/aries/blob/trunk/jpa/jpa-
container-context/src/main/java/org/apache/aries/jpa/
container/context/transaction/impl/JTAEntityManagerHandler.java
As you see there is a lot of special processing for the different calls to
EntityManager. Some calls we even swallow. My hope is that with a plain
EntityManager inside a ThreadLocal most of that complexity can be removed.
After all it is pretty difficult to prove that our current wrapping
solution works correctly in all imaginable cases.
The wrapping is also especially difficult as we handle JPA 2.0 and 2.1 at
the same time as we have to wrap two different versions of the
EnitityManager interface.
Christian
On 06.11.2014 12:36, Giuseppe Gerla wrote:
Hi Christian
I am not an expert on JTA, so for me it is not fully clear the problem
you're facing.
From my experience I can say, however, that the use of ThreadLocal is not
recommended.
From my point of view, it would be better to use something like this:
@Singleton
@Transactional
public class TaskServiceImpl implements TaskService {
EntityManagerFactory emf;
public void updateTask(Task task) {
emf.createEntityManager().persist(task);
}
}
Regards
Giuseppe
--
Christian Schneider
http://www.liquid-reality.de
Open Source Architect
http://www.talend.com
--
Christian Schneider
http://www.liquid-reality.de
Open Source Architect
Talend Application Integration Division http://www.talend.com