EntityManagers are one of the most fundamental objects in JPA. It is quite easy to understand their basic role, however, it can be quite confusing when we look at the possible configurations in which we can use them.
EntityManagers can differ according to:
To make things more complicated, not all combinations are allowed. For example, Container-Managed EntityManagers can work only with transaction management provided by JTA API.
The above diagram represents possible EntityManager’s configuration options:
The main feature of Application-Managed EntityManagers is that they are managed by the application ( by the programmer). It means, that the application code is responsible for their creation and closing.
To create an EntityManager object, we need to have javax.persistence.EntityManagerFactory
object, which can be obtained in two ways:
@PersistenceUnitprivate EntityManagerFactory entityManagerFactory;
EntityManagerFactory emf = Persistence.createEntityManagerFactory("unitname");
As the diagram above shows, PersistenceContext for Application-Managed EntityManagers is by default EXTENDED
,
which means that it is not bound only to one transaction.
In this case, a new PersistenceContext is created when the method createEntityManager from EntityManagerFactory interface is invoked, and get detached when we invoke EntityManager’s close method or when the bean is serialized.
private EntityManagerFactory emf;private EntityManager em;public void run() {methodA(); // create persistence contextmethodB(); // perform some operationsmethodC(); // detach persistence context}private void methodA() {em = emf.createEntityManager(); // create persistence context}private void methodB() {// do some more em operations}private void methodC() {em.close();}
In the above example, all three methods: methodA, methodB, and methodC work with the same PersistenceContext. It is important to remember, that every invocation of the createEntityManager method from the EntityManagerFactory interface will return an EntityManager object with a different PersistenceContext.
public void run(){// method A and B work with a different persistence contextmethodA();methodB();}private void methodA() {em = emf.createEntityManager(); // create persistence context// perform some em operations}private void methodB() {em = emf.createEntityManager(); // create another persistence context// perform some em operations, this time in a different persistence context}
Application-managed EntityManager for transaction management can use JDBC (RESOURCE_LOCAL) or JTA API.
Which one will be used depends on the configuration in persistence.xml
. The important thing is that JTA API can be used
only when we work with a Java EE container.
In JDBC API, for transaction management responsible is javax.persistence.EntityTransaction
interface.
To obtain an instance that implements this interface, we have to use the getTransaction
method from the EntityManager object.
Example of transaction management using JDBC API:
EntityManager em = emf.createEntityManager();EntityTransaction tx = null;try {tx = em.getTransaction();tx.begin();// do some worktx.commit();}catch (RuntimeException e) {if ( tx != null && tx.isActive() )tx.rollback();throw e; // or display error message}finally {em.close();}
In JTA, we manage transactions using javax.transaction.UserTransaction
interface. However, we don’t have to use it
because, by default in JTA, the container is responsible for managing our transactions- it is called CMT
(Container-Managed Transactions). In this case, the container will start the transaction as soon as the method
begins and will commit it just before the method exits. All we need to do is manage our EntityManger
(as we work in Application-Managed mode):
public void method() {// start of the transactionEntityManager em = null;try {em = emf.createEntityManager(); // new persistence context// do some operations with EntityManager} finally {if (em != null) {em.close(); // end persistance Context}// end of the transaction}
While working with JTA API, if we want to manage our transaction manually, we have to annotate our bean with
@TransactionManagement
annotation with TransactionManagementType
set to BEAN
value. In this case, we have to:
@Stateless@TransactionManagement(TransactionManagementType.BEAN)public class EJBBean{ ... }
Now we can manage our transaction using javax.transaction.UserTransaction
interface. We can obtain it at least
in two ways: we can inject it with @Resource
annotation, or we can inject javax.ejb.EJBContext
interface which
has method getUserTransaction
that returns an instance of the UserTransaction interface.
Example of managing transactions in JTA:
@Stateless@TransactionManagement(TransactionManagementType.BEAN)public class EJBBean {...@ResourceUserTransaction ut;public void methodA() throws Exception {EntityManager em = null;try {ut.begin();em = emf.createEntityManager(); //perform some update/insert with emut.commit();} catch (Exception ex) {ut.rollback();throw ex;} finally {if (em != null) {em.close();}}...
Container-managed EntityManagers are those kind of EntityManagers that are created and closed by the container.
To make the EntityManager container-managed, all we need to do is inject it with @PersistenceContext
annotation,
with unitName
defined in the persistence.xml
file:
@PersistenceContext(unitName ="unitName")private EntityManager entityManager;
Because Container-Managed EntityManager is managed by the container, its PersistenceContext also is managed by the container-which by default is transaction-scoped. This means that the PersistenceContext lives as long as the transaction lives.
We can extend PersistenceContext to extended scope by adding type=PersistenceContextType.EXTENDED
to @PersistenceContext
annotation:
@PersistenceContext(unitName="unitName", type=PersistenceContextType.EXTENDED)EntityManager em;
In this case, because PersistenceContext is associated with EntityManager, it lives as long as the bean lives.
We can remove it programmatically by invoking the method with @Remove
annotation, which will remove our bean from the container:
@Removepublic void remove() {}
In Container-Managed EntityManager we can use only JTA API for transaction management. We can handle the transactions manually or let the container do it (the same as in Application-Managed EntityManager).
If we let the container manage our transaction and will have Container-Managed EntityManager, sample insert method will look like this:
@PersistenceContext(unitName="unitName")EntityManager em;public void insert(ClassStudent student) {em.persist(student);}
Quick Links
Legal Stuff