This link explained it:
https://stackoverflow.com/questions/11063567/java-cdi-persistencecontext-and-thread-safety/13607626#13607626
Here I provide some test results and more details.
Repository1.java
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.Path;
@Stateless
@Path(“/test”)
public class Repository1 {
@Inject
private Repository2 rep2;
@PersistenceContext(unitName = “yourunitname”)
private EntityManager entityManager;
@Path(“/test”)
public void doSomething() {
System.out.println(“Repository1—“ + this.toString() + “—“ + System.identityHashCode(entityManager) + “—“ + entityManager.getClass().getSimpleName() + “—“ + entityManager.getDelegate() + “—“ + entityManager.getDelegate().hashCode());
rep2.doSomethingAgainInTheSameTransaction();
}
}
Repository2.java
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class Repository2 {
@PersistenceContext(unitName = “yourunitname”)
private EntityManager entityManager;
//@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doSomethingAgainInTheSameTransaction() {
System.out.println(“Repository2—“ + this.toString() + “—————“ + System.identityHashCode(entityManager) + “—“ + entityManager.getClass().getSimpleName() + “—“ + entityManager.getDelegate() + “—“ + entityManager.getDelegate().hashCode());
}
}
when you run Repository1.doSomething(), it will start a transaction and call rep2.doSomethingAgainInTheSameTransaction(), because the defaultTransactionAttributeType of rep2.doSomethingAgainInTheSameTransaction() is REQUIRED so rep2.doSomethingAgainInTheSameTransaction() will run under the same transaction of Repository1.doSomething(). Under the same transaction, persistenceContext and entityManager should be the same. If you compare the output in the two classes, the entityManager.getDelegate().hashCode() is the same, but System.identityHashCode(entityManager) is different. That is because when the instances of Repository1 and Repository2 are initiated, entityManager is injected by container, but the injected entityManager is NOT the EntityManager object, it is the proxy of an entityManager, so System.identityHashCode(entityManager) is different in the two classes, which injected two different objects of entityManager proxy to entityManager and the two different objects of entityManager proxy delegate calls to the same EntityManager object or Hibernate Session in this case, so entityManager.getDelegate().hashCode() is the same.
If you uncomment this line//@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) in Repository2.java and run it again, both entityManager.getDelegate().hashCode() and System.identityHashCode(entityManager) are different. Because rep2.doSomethingAgainInTheSameTransaction() runs in a separate transaction and this transaction has a different persistenceContext and entityManager(different entityManager proxy which delegates calls to a different EntityManager object or Hibernate Session in this case).
Read Full Post »