Reputation: 623
Consider this scenario:
@Stateless
public class A{
@PersistenceContext
private EntityManager em;
@EJB
B b;
@EJB
C c;
public void doSomeWork(){
b.doSomeWork();
c.doSomeWork();
em.persist(someStuff);
}
}
@Stateless
public class B{
@PersistenceContext
private EntityManager em;
public void doSomeWork(){
//Do stuff
em.persist(stuff)
}
}
@Stateless
public class C{
@PersistenceContext
private EntityManager em;
public void doSomeWork(){
//Do stuff
em.persist(stuff)
}
}
In this scenario I'm using three different EntityManagers for the same transaction (started in method doSomeWork()
from class A
Now, the same transaction but with only one EntityManager:
@Stateless
public class A{
@PersistenceContext
private EntityManager em;
@EJB
B b;
@EJB
C c;
public void doSomeWork(){
b.setTheEntityManager(em);
b.doSomeWork();
c.setTheEntityManager(em);
c.doSomeWork();
em.persist(someStuff);
}
}
@Stateless
public class B{
private EntityManager em;
public void setTheEntityManager(EntityManager em){
this.em = em;
}
public void doSomeWork(){
//Do stuff
em.persist(stuff)
}
}
@Stateless
public class C{
private EntityManager em;
public void setTheEntityManager(EntityManager em){
this.em = em;
}
public void doSomeWork(){
//Do stuff
em.persist(stuff)
}
}
I've been reading about the EntityManager lifecycle but I just can't get if there's any advantage (in terms of performance, database connections,..) in the second scenario. My first answer would be yes because there's only one EntityManager but on the other hand I don't see any code examples using this approach (passing the EntityManager from EJB to EJB). Also, the Oracle Docs say "By automatically propagating the persistence context, application components don’t need to pass references to EntityManager instances to each other in order to make changes within a single transaction. The Java EE container manages the lifecycle of container-managed entity managers."
Upvotes: 2
Views: 30
Reputation: 8837
Anything you @Inject or @Resource from the container should never ever be passed somewhere else. That's a surefire way to create a memory leak and/or undefined behavior. There also is no advantage to doing the second, as the container automatically injects the correct EntityManager for you every time :)
So in short, never ever do the second scenario, always do the first scenario. The container is actually inject a Proxy that routes you to the correct (the same in your case since you haven't exited your transaction boundary) entity manager.
What's happening is the call into a.doSomeWork()
has an implied TransactionAttribute.Required. If a transaction has not already been started, the container starts one for you. Subsequent calls to B and C now participate in that transaction. When you exit a.doSomeWork()
, assuming that's where the transaction started, that's where the transaction commits. Anything done by A, B, and C all occur in the same transaction.
Upvotes: 1