Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Tackling RESOURCE_LOCAL Vs. JTA Under Java EE Umbrella and Payara Server

DZone's Guide to

Tackling RESOURCE_LOCAL Vs. JTA Under Java EE Umbrella and Payara Server

Let's tackle these important features under the Java EE umbrella.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

Image title

Learning JPA is a road marked with a lot of questions. Some of the notorious questions include: "What is actually a persistence-unit?," "What is an extended persistence-context?," "Why is wrong to fetch read-only data as entities?," "Why should I care aboutRESOURCE_LOCALorJTA?," and so on and forth. 

This article targets people that are confused by the JPA transaction types,RESOURCE_LOCAL, andJTA. But, let's take it step by step.

What Is a Persistent-Unit?

Think to the persistent-unit as a box holding all the needed information for creating anEntityManagerFactoryinstance. Among this information, we have details about the data source (JDBC URL, user, password, SQL dialect, etc), the list of entities that will be managed, and other specific properties. And, of course, we have the persistent-unit transaction type, which can beRESOURCE_LOCALorJTA. We can specify all these details in an XML file calledpersistence.xmlor, at the API level, via an implementation of javax.persistence.spi.PersistenceUnitInfo.

In both cases, we identify a persistent-unit by the name that we choose. We can have multiple persistent units and identify them by name.

<!-- persistence.xml -->
<persistence version="2.1" xmlns=...>
    <persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL/JTA">
    ...
    </persistence-unit>
</persistence>
// flavor of PersistenceUnitInfo implementation
import javax.persistence.spi.PersistenceUnitInfo;
...
public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {

    private final String persistenceUnitName;
    private PersistenceUnitTransactionType transactionType = 
        PersistenceUnitTransactionType.JTA/RESOURCE_LOCAL;
    ...
}      


What Is EntityManagerFactory?

As its name suggests, anEntityManagerFactoryis a factory capable to create on-demandEntityManagerinstances. 

Basically, we provide the needed information via the persistent-unit, and JPA can use this information to create anEntityManagerFactorythat exposes a method named,createEntityManager(), which returns a new application-managedEntityManagerinstance at each invocation.

We open an EntityManagerFactoryvia injection (@PersistenceUnit) or via Persistence.createEntityManagerFactory(). We can check the status of anEntityManagerFactoryvia theisOpen()method, and we can close it via theclose()method. If we close anEntityManagerFactory, all its entity managers are considered to be in the closed state.

What Is EntityManager?

In order to understand what is anEntityManager,let's talk about what's happening with the data extracted from the database.

  • Fetching data from the database results in a copy of that data in memory (usually referred to as the data snapshot). This zone of memory that holds the fetched data is known and referred to as the persistence-context or the first-level cache or simple the cache. This is a strong reason for NOT fetching data as entities if we don't plan to modify them. Read-only data will consume memory resources adding pointless performance penalties.

  • After fetching operation, the fetched data snapshot lives outside the database, in memory. We access/manage this data via entities (so, via Java objects), and for facilitating this context, JPA applies specific techniques that transform the fetched raw data into this manageable representation. This is another strong reason for NOT fetching data as entities if we don't plan to modify them. Read-only data should be transformed before storing, and this will consume CPU resources adding pointless performance penalties.

Image title

  • One single active persistence-context should be allocated to the currently active transaction. During the current transaction lifespan, we can manipulate the data stored in the persistence-context via theEntityManagermethods (verbs). Actions, as finding objects, persisting them, removing objects from the database and so on, are specific to the EntityManager. In a more simplistic day-to-day chat, there is nothing wrong to say that the EntityManagerinstance is the persistence-context. As a rule of thumb, avoid using more than one persistence-context per transaction.

Image title

  • After we modify the data from the persistence-context, we want to propagate these modifications to the database. This action is known as flush, and it can be automatically or manually triggered multiple times during a transaction lifespan. We say that at the flush time we synchronize the persistence-context to the underlying database. There are different flushing strategies, but probably, the most used is AUTO(relying on the default flush strategy) andCOMMIT(flushing occurs prior to transaction commit). Think to the flush action as the bunch of SQL statements needed to be sent to the database in order to propagate our modifications.

Image title

  • Once the current transaction is inactive/completed (by commit or rollback), all objects that were in the persistence-context are detached. Detaching all entities take place when theEntityManageris cleared via theclear()method or closed via theclose()method. Certain entities can be detached by calling a dedicated method named detach() (or evict()in Hibernate). This means that further modifications of these objects will not be reflected in the database. This is possible only by re-attaching the objects via themerge()operation (andupdate()in Hibernate) in the context of an active transaction. This is the default behavior of a transactional-scopedEntityManager(known as Transactional Persistence Context). There is also the EntityManagerthat span across multiple transactions (extended-scope) known as Extended Persistence Context.

  • At detaching, objects are leaving the persistence-context and continue to live outside of it. This means that JPA will not manage them anymore, no more special treatment, they are just some usual Java objects. For example, callingEntityManager.remove(detached_entity)will throw a meaningful exception.

Image title

RESOURCE_LOCAL Vs. JTA

Quiz:

1. Who is gonna manage the transactions?

A. You (in the application)        B. The application server

2 Who is gonna manage the persistence-context lifespan?

A. You (in the application)        B. The application server

3. Transactions should span multiple persistent-units (databases) or systems (e.g., JMS, JCA, etc)?

A. No        B. Yes

Well, if you answered "A" to all questions, then you needRESOURCE_LOCAL. In this case, the transactions are local to the JPA persistence-unit.

But, if you answered at least one time "B," then you needJTA. In other words, the transactions are managed by the application server's JTA implementation.

Now, let's see what efforts imply the usage ofRESOURCE_LOCALrespectivelyJTA .

Using RESOURCE_LOCAL

<persistence-unit transaction-type="RESOURCE_LOCAL">


Once you write this line in thepersistence xml, you are responsible to manage theEntityManagerlifespan. Having this responsibility on your shoulders requires some skills and knowledge under your toolbelt:

Obtain an EntityManagerFactory

In order to create an EntityManager, you need anEntityManagerFactoryin your application. You can achieve this in at least two ways: via thePersistence.createEntityManagerFactory()method or via injection using the@PersistenceUnit annotation:

// using injection via @PersistenceUnit
@PersistenceUnit(unitName = "MyPU")
private EntityManagerFactory emf;  

// using Persistence.createEntityManagerFactory() method
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MyPU");


Do not confuse@PersistenceUnitwith@PersistenceContext

Obtain an EntityManager

Having anEntityManagerFactoryis good but not enough. Further, we need anEntityManagerinstance. For this, we call thecreateEntityManager()method like in the following snippet of code:

// create a brand new EntityManager instance
EntityManager em = emf.createEntityManager();


Notice that each call of thecreateEntityManager()method will return a brand new application-managed EntityManager; therefore, a brand new application-managed persistence-context. Is your responsibility to ensure that it is exactly oneEntityManagerinstance for the current transaction (only one active persistence-context). Having two or more persistence-context in the same transaction may lead to exceptions and weird behaviors.

Define Transaction Boundaries

Further, each call of anEntityManageraction (e.g., find, persist, remove, etc) should be wrapped by an active transaction. Basically, theEntityManagerverbs should be demarcated by explicit calls of thebegin()andcommit()methods. We say that we use theEntityTransaction API to demarcate the boundaries of a transaction. Betweenbegin()and commit()our transaction is active.

EntityTransaction tx = em.getTransaction();

tx.begin();

em.find(...);
em.persist(...);
...

tx.commit();  


Rollback 

Rollback a failed transaction is your responsibility as well. This means that you should intercept specific exceptions and explicitly call therollback()method. This ensures that a failed transaction will lead to reverting the database in the state before the transaction begun. Don't conclude from here that read-only queries should not run in a transaction. This is not true! It is advisable to run the read-only query in a transaction as well.

EntityTransaction tx = em.getTransaction();

try {
    tx.begin();

    em.find(...);
    em.persist(...);
    ...

    tx.commit();  
} catch (RuntimeException/Exception e) {       

      if (tx != null && tx.isActive()) {
          tx.rollback();
      }

      // eventually log or throw the exception
}


Clear and Close EntityManager

The last responsibility is pretty straightforward. Once the transaction was committed, we need to detach the entities from the persistence-context. For this, we can callclear()orclose(). By callingclear(), the managed entities become detached, but theEntityManagercan be re-used in other transactions. This is a common technique in batching implementation. During batching, we keep on accumulating managed entities in the persistence-context, and this can lead to significant performance penalties and/or OOM errors. In order to avoid these issues, we must keep the persistence-context as slim as possible and this can be accomplished by periodically calling clear()

When theEntityManageris no more useful, we must close it by calling theclose()method. In this case, for the next transaction, we need to create a brand newEntityManager.

EntityTransaction tx = em.getTransaction();

try {
    tx.begin();

    em.find(...);
    em.persist(...);
    ...

    tx.commit();  
} catch (RuntimeException/Exception e) {       

      if (tx != null && tx.isActive()) {
          tx.rollback();
      }

      // eventually log or throw the exception
} finally {            

    if (em != null && em.isOpen()) {                                        
        em.close();                                
    }          
}


Using JTA

<persistence-unit transaction-type="JTA">


Once you write this line in persistence.xml, you pass most of the responsibilities of managingEntityManager to the container/application server. This should be an application server that has/support a transaction manager (e.g., Payara Server).

Obtain an EntityManager

In order to obtain anEntityManager, we can use the@PersistenceContextannotation, as follows:

@PersistenceContext(unitName = "MyPU")
private EntityManager em;


Do not confuse@PersistenceContextwith@PersistenceUnit

The injectedEntityManageris provided by the container. This is a reference to the persistence-context associated with a JTA transaction.

We want exactly one persistence-context per transaction. Using a JTA unit with anEntityManager created by the container, it will always guarantee this statement.

Once we inject anEntityManager, we can simply call its methods. Transaction creation, transaction demarcation boundaries, rollback, flushing and clearing the EntityManagerat JTA transaction commit time are the container responsibilities.

So, in the case of classicJTA, we don't need all the plumbing code needed in case of RESOURCE_LOCAL. We just exploit theEntityManagerand allow the container to do the rest of the job for us.

Types of Persistence Contexts and Transactions

Image title

If we try to categorize persistence-context by its scope in a Java EE application, we obtain:

Transactional-Scoped and Extended Persistent Context

Transactional-scoped persistence-context is specific to stateless beans. Since each invocation of a stateless bean business method may use a different instance of that bean, a transaction must be completed at the end of the business method execution (each business method has its own transaction).

Extended persistence-context is allowed only in a stateful bean. Each invocation of a stateful bean business method will use the same instance; therefore, we can provide a state via an extended persistence-context that lives over multiple transactions. Basically, the persistence-context lives beyond the scope of a transaction.

Image title

In JTA, we can control if theEntityManageris extended or transactional during theEntityManagerinjection:

@PersistenceContext(type=javax.persistence.PersistenceContextType.EXTENDED)
EntityManager em;


If we try to categorize persistence-context and transactions depending on who is responsible to manage their lifespans in a JavaEE application, we obtain:

Container-Managed Persistence Context 

Specific toJTA transactions, by Container-Managed Persistence Context, we understand that the container is responsible to provide(inject) a ready-to-go persistence-context that it is aware of the currently active transaction. Moreover, it is container responsibility to flush and close the persistence-context.

@PersistenceContext(unitName = "MyPU")
private EntityManager em;


Application-Managed Persistence Context 

Can be used inJTAandRESOURCE_LOCALtransactions. By Application-Managed Persistence Context, we understand that we are responsible to create and remove the persistence-context. Every application-managed persistence-context has the extended scope. This means that when the transaction is complete, theEntityManageris not cleared or closed. Clear/close the EntityManageris recommended in stateless beans where the extended scope is pointless.

@PersistenceUnit(unitName = "MyPU")
private EntityManagerFactory emf;
...
EntityManager em = emf.createEntityManager();
...
em.clear()/em.close();


Container-Managed Transactions (CMT)

Specific toJTAtransactions, by Container-Managed Transactions, we understand that the container is responsible for the whole transaction lifespan (create, begin, commit, rollback). Optionally, we can use javax.ejb.TransactionAttributefor defining the transaction context (defaults toREQUIRED).

@Stateless
@TransactionAttribute(TransactionAttributeType.NEVER)
public class SomeBean { 
   ...
}


Bean-Managed Transactions (BMT)

Specific toJTAtransactions, by Bean-Managed Transactions, we are responsible for starting, rolling back or committing the transaction by explicitly call begin(),commit()androllback()methods. We’ll be using the JTA transactions level, so we won’t be usingjavax.persistence.EntityTransaction. BMT must interact with the JTA transaction manager through thejavax.transaction.UserTransactioninterface.

@Resource
private UserTransaction userTransaction;


Application-Managed Transactions

Specific toRESOURCE_LOCALtransactions, by Application-Managed Transactions, we are responsible for starting, rolling back or committing the transaction by explicitly callbegin()commit() and rollback() methods. We’ll be using theRESOURCE_LOCALtransactions level, so we use thejavax.persistence.EntityTransactionviaEntityManager.getTransaction()method.

EntityTransaction tx = em.getTransaction();


Time for Applications

The applications developed in this article requires Payara Server

Please follow this article, steps 1-4 in order to install and start a Payara Server instance and configure a MySQL data source in Payara.

We use the JPA implementation, EclipseLink.

Writing the persistence.xml Descriptor

Thepersistence.xmldescriptor is specific to Java EE applications and it contains all the details related to our persistent-units. Commonly, we have a single persistent-unit, but more are allowed as well. From the transaction-type perspective, the most common persistent-units are:

  • persistent-unit forJTAtransaction-type

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="MyPU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/players</jta-data-source>   
        <class>com.sample.model.Player</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>      
            <property name="javax.persistence.schema-generation.database.action" 
                      value="drop-and-create"/>
        </properties>
    </persistence-unit>
</persistence>


  • persistent-unit forRESOURCE_LOCAL transaction-type with data source configured on the application server

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <non-jta-data-source>jdbc/players</non-jta-data-source>
        <class>com.sample.model.Player</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>      
            <property name="javax.persistence.schema-generation.database.action" 
                      value="drop-and-create"/>
        </properties>
    </persistence-unit>
</persistence>


  • persistent-unit forRESOURCE_LOCAL transaction-type with data source configured via properties:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL">        
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.sample.model.Player</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>  
            <property name="javax.persistence.jdbc.driver" 
                      value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" 
                      value="jdbc:mysql://localhost:3306/db_players
                             ?createDatabaseIfNotExist=true&amp;useSSL=false"/>
            <property name="javax.persistence.jdbc.user" 
                      value="root"/>
            <property name="javax.persistence.jdbc.password" 
                      value="root"/>    
            <property name="javax.persistence.schema-generation.database.action" 
                      value="drop-and-create"/>
        </properties>
    </persistence-unit>
</persistence>


Classic RESOURCE_LOCAL Application

A classicRESOURCE_LOCALapplication relies on application-managed persistence-context and transactions. Notice how we inject the EntityManagerFactory, create and close theEntityManager, create and demarcate the transaction boundaries, and rollback it in case of an exception.

@Path("player")
public class PlayerResource {

    @PersistenceUnit(name="MyPU")
    private EntityManagerFactory emf;

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Player generatePlayer() {

        Player player = new Player();
        player.setName(...);
        player.setCity(...);
        player.setAge(...);

        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        try {
            tx.begin();
            em.persist(player);
            tx.commit();

        } catch (Exception e) { // or use explicit exception            

            if (tx != null && tx.isActive()) {
                tx.rollback();
            }

            throw e;

        } finally {
            if(em != null && em.isOpen()) {
                em.close();
            }
        }

        return player;
    }
}


The source code can be found on GitHub.

Classic JTA Application

A classic JTA application relies on container-managed persistence-context and transactions. So, the container will inject the JTAEntityManagerand will take care of the JTA transactions:

@Path("player")
@Stateless
public class PlayerResource {

    @PersistenceContext(unitName = "MyPU")
    private EntityManager em;

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Player generatePlayer() {

        Player player = new Player();
        player.setName(...);
        player.setCity(...);
        player.setAge(...);

        em.persist(player);

        return player;
    }
}


The source code can be found on GitHub.

Application-Managed EntityManager and CMT

In this case, we manage theEntityManagerby creating (via the injected EntityManagerFactory) and closing it. The container is responsible to manage the JTA transactions. This means that you can use the JTA transactions in your application-managedEntityManager. TheEntityManageris JTA aware and it will automatically join the container-managed JTA active transaction.

@Path("player")
@Stateless
public class PlayerResource {

    @PersistenceUnit(unitName = "MyPU")
    private EntityManagerFactory emf;

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Player generatePlayer() {

        Player player = new Player();
        player.setName(...);
        player.setCity(...);
        player.setAge(...);

        EntityManager em = emf.createEntityManager();
        em.persist(player);
        em.close();

        return player;
    }
}


The source code can be found on GitHub.

Application-Managed EntityManager and BMT

In this case, we manage theEntityManagerby creating (via the injected EntityManagerFactory) and closing it. We also inject theUserTransactionand use it to begin, commit and rollback the JTA transaction. In this case, theEntityManagerwill automatically join the active JTA transaction only if we create it inside an active JTA transaction. Creating it outside of the JTA transaction will not result in an exception, but then nothing will be committed.

@Path("player")
@TransactionManagement(TransactionManagementType.BEAN)
public class PlayerResource {

    @PersistenceUnit(unitName = "MyPU")
    private EntityManagerFactory emf;

    @Resource
    private UserTransaction userTransaction;

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Player generatePlayer() throws Exception { // or use explicit exception

        Player player = new Player();
        player.setName(...);
        player.setCity(...);
        player.setAge(...);

        EntityManager em = null;
        try {
            userTransaction.begin();
            em = emf.createEntityManager();

            em.persist(player);

            userTransaction.commit();
        } catch (Exception e) { // or use explicit exceptions

            if (userTransaction != null) {
                userTransaction.rollback();
            }

            throw e;

        } finally {            
            if (em != null && em.isOpen()) {
                em.close();
            }
        }

        return player;
    }
}


The source code can be found on GitHub.

Application-Managed EntityManager Join BMT

In this case, the application-managedEntityManageris created before the JTA transaction starts. In order to join this transaction, we explicitly call thejoin()method.

@Path("player")
@TransactionManagement(TransactionManagementType.BEAN)
public class PlayerResource {

    @PersistenceUnit(unitName = "MyPU")
    private EntityManagerFactory emf;

    @Resource
    private UserTransaction userTransaction;

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Player generatePlayer() throws Exception { // or use explicit exception

        Player player = new Player();
        player.setName(...);
        player.setCity(...);
        player.setAge(...);

        EntityManager em = emf.createEntityManager();
        try {
            userTransaction.begin();
            em.joinTransaction();

            em.persist(player);

            userTransaction.commit();
        } catch (Exception e) { // or use explicit exceptions

            if (userTransaction != null) {
                userTransaction.rollback();
            }

            throw e;

        } finally {            
            if (em != null && em.isOpen()) {
                em.close();
            }
        }

        return player;
    }
}


The source code can be found on GitHub.

Container-Managed EntityManager and BMT

In this case, we allow the container to inject and manage theEntityManagerand we take care of starting, committing and rollback the JTA transaction. TheEntityManagerwill automatically join the JTA active transaction.

@Path("player")
@TransactionManagement(TransactionManagementType.BEAN)
public class PlayerResource {

    @PersistenceContext(unitName = "MyPU")
    private EntityManager em;

    @Resource
    private UserTransaction userTransaction;

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Player generatePlayer() throws Exception { // or use explicit exceptions

        Player player = new Player();
        player.setName(...);
        player.setCity(...);
        player.setAge(...);

        try {
            userTransaction.begin();
            em.persist(player);
            userTransaction.commit();
        } catch (Exception e) { // or use explicit exceptions            

            if (userTransaction != null) {
                userTransaction.rollback();
            }

            throw e;
        }

        return player;
    }
}


The source code can be found on GitHub.

Done! Notice that our examples are based on JAX-RS resources. As in the JAX-RS specifications, a resource can be a@Singletonor@StatelessEJB. If you need a@StatefulEJB (e.g., for Extended Persistence Context), then rely on classic EJBs.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
jpa ,jta ,transactions ,jdbc ,java ,tutorial ,entitymanager

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}