Wednesday, March 27, 2013

Types of Entity Managers: Application-managed EntityManager

JPA specification defines few types of EntityManagers / Persistence Contexts. We can have:

  • extended and transactional-scoped EntityManagers,
  • container-managed or application-managed EntityManagers.
  • JTA or resource-local EntityManager,

Besides the above distinction, we also have two main contexts in which EntityManager / Persistence Context can exist – Java EE and Java SE. Not every option is available for Java EE and not every is possible in Java SE. In the rest of the post I refer to the Java EE environment.

Ok, so before we’ll proceed to the real topic of this post — which is the behaviour of the EntityManager in Java EE created manually using EntityManagerFactory — let’s just shortly describe the above EM types.

Extended vs transactional-scoped

This feature tells us if the EntityManager’s operations might span across multiple transactions. By default the Transactional Persistence Context is used which means that all changes are flushed and all managed entities become detached when the current transaction commits. The extended scope is available only for Stateful EJBs; it makes perfectly sense as the SFSBs can save the state, so end of one business method doesn’t necessary means the end of the transaction. With the SLSB the story is different – we have business method that must end when the business method finishes because in next invocation we don’t have an idea which EJB instance we’ll end in. One method = one transaction; only transactional-scoped EntityManager is allowed for SLSB. You can control if the EntityManager is extended or transactional during the EntityManager injection:

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

By default it’s javax.persistence.PersistenceContextType.TRANSACTION. As a side note – using extended EntityManager might allow you to create some interesting solutions; take a look at Adam Bien’s no-transactional bean with transactional save method trick. He uses this approach to make all the changes automatically flushed when the transaction starts and ends (and he actually do that by invoking special, artificial method.) Extended and transaction scoped PersistenceContext are allowed only in case of container-managed EntityManagers.

Container-managed vs application-managed

In great majority of Java EE applications you’re just injecting the EntityManager with @PersistenceContext like this:

@PersistenceContextEntityManager em;

This actually means that you’re letting the container to inject the EntityManager for your (the container creates it from the EntityManagerFactory behind the scenes.) This means that your EntityManager is container-managed. Alternatively, you can create an EntityManager by yourself – from the EntityManagerFactory. You can obtain it by injection:

@PersistenceUnitEntityManagerFactory emf;

Then to get the EntityManager you need to invoke emf.createEntityManager(). And here it is – you’re now using the application-managed EntityManager. The application (you) is responsible for creation and removal of EntityManager. Every application-managed Persistence Context has the extended scope.

You might use if if you want to have control over created EM – e.g. if you want to set some property to the underlying JPA implementor or just plug yourself before the business method put it hands on it. You will, however need to move the created EntityManager across multiple beans involved in the transaction – the container won’t do it for you and every time you invoke emf.createEntityManager() you’re creating an EntityManager that is connected to the new PersistenceContext. You might use the CDI for EntityManager’s sharing, but that’s the topic of one of the last sections.

JTA vs resource-local

This property defines if you want the JTA to manage your EntityManager’s transactions or if you want to use its direct API to begin and commit. If you’re using container-managed EntityManager it automatically means that you have to use JTA EntityManager. If you’re using application-managed EntityManager, you can have it JTA or resource-local. In the real-life it means that if you’re using JTA EntityManager you take care just of the higher-level transactions management either:

  • declaratively; using annotations or XML JTA transactions attributes or,
  • programmatically; using javax.transaction.UserTransaction.

If you’re using the resource-local EntityManager you need to go a bit deeper and use EntityManager.getTransaction() that returns javax.persistence.EntityTransaction and invoke commit(-), begin(-), rollback(), etc. You define this feature in persistence.xml using transaction-type attribute:

<?xml version='1.0' encoding='UTF-8'?><persistence ...>    <persistence-unit transaction-type='RESOURCE_LOCAL' ... ></persistence>

The other possible value (and default when transaction-type is not defined) is JTA.

Application-managed JTA EntityManager in Java EE

As much as this subtitle sounds complex, knowing all the previous types of EntityManagers and PersistenceContexts you should understand exactly what if refers to.

  • “Application-managed” means that we’ll be injecting @PersistenceUnit EntityManagerFactory instead of EntityManager,
  • “Java EE” because these examples (published on github) are to be used only in Java EE Application Server,
  • “JTA” because we’ll be using the JTA transactions level, so we won’t be using javax.persistence.EntityTransaction.

Now the first thing you need to realize is how you use the JTA transactions. There are two types of JTA transactions management – container (CMT) and bean managed (BMT). The Container Managed JTA transactions (CMT) means that you use the javax.ejb.TransactionAttribute for defining if the tx should be active and where the transaction boundaries are. This is the default JTA management type. Alternative, you can choose to demarcate the JTA transactions yourself. This is called the Bean Managed JTA Transactions (BMT.) The application (you) is responsible for starting, rolling back or committing the transaction. How can you control a JTA transaction? You do that using javax.transaction.UserTransaction.

How do you obtain one? Well, there are at least 3 ways to do this:

  • it’s bound to the JNDI in the component-private namespace (java:comp/UserTransaction), so you can just look it up using InitialContext or SessionContext,
  • you can use SessionContext to access it – SessionContext#getUserTransaction(),
  • because it’s bound in the well-known JNDI name, you can let the container inject it using: @Resource UserTransaction utx;.

If you have UserTransaction you can start demarcating what is to be executed within the transaction. Notice that you’re still controlling the JTA transactions – you’re not even touching the EntityManager’s resource-local transactions.

When The EntityManager is in The JTA Transaction?

Without the previous introduction you might think that the application-managed EntityManager means that you’re on your own for everything – creating, sharing EntityManager, begining tx, commiting, closing. However, knowing all the above differences you know that you can use the JTA transactions in your application-managed EntityManager. But the question is – how to make it aware of the active JTA transaction? If we have a container-managed EntityManager we know that the container manages it all, but in case we’re on our own – how do we do that? Actually it depends where the EntityManager was created by us. Find some examples below (the complete code can be found on my github account:

Case 1: We invoke the following code without the active transaction (so we have TransactionAttribute.NEVER or TransactionAttribute.NOT_SUPPORTED in case of CMT or we didn’t invoke UserTransaction.begin() in case of BMT:

EntityManager em = emf.createEntityManager();  em.persist(new Customer(firstName, lastName));

Results: The EntityManager operations don’t thrown any exception while persisting but none of the changes are committed. There is no active transaction, so no changes are made.

Case 2: We invoke the following code using BMT:

utx.begin();EntityManager em = emf.createEntityManager();em.persist(new Customer(firstName, lastName));utx.commit();

Results: The new data is properly persisted during JTA commit (in the last line.)

Case 3: We invoke the following code using BMT:

EntityManager em = emf.createEntityManager();utx.begin();em.persist(new Customer(firstName, lastName));utx.commit();

Results: The EntityManager is outside of the transaction because it was created before the JTA transaction was started. The changes are not persisted despite the commit of the JTA transaction. No exceptions are thrown.

In case of the second example you might ask yourself – is it possible to firstly create an EntityManager, then start a transaction and finally somehow make the EntityManager aware of the surrounding tx? And if fact yes, you can do that and that’s exactly what the EntityManager#joinTransaction() method is for. Following two cases should show you how it can be used:

Case 4: We invoke the following code using BMT:

EntityManager em = emf.createEntityManager();  utx.begin();em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();   

Results: Here we explicitly told the EntityManager to join the active JTA transaction. In the result, the EntityManager will flush all its changes during JTA commit.

Case 5: We invoke the following code using BMT:

EntityManager em = emf.createEntityManager();utx.begin();em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();utx.begin();em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();    

Results: Both EntityManager operations are properly persisted. Here we’ve shown that the application-managed Persistence Context can span across multiple JTA transactions (note that we didn’t create another EntityManager but just reused the one used in previous transaction.) And here you can see what the JPA specs (JPA 2.0 Final Release) tells you regarding application-managed Persistence Context:

7.7 Application-managed Persistence Contexts

When a JTA application-managed entity manager is used, if the entity manager is created outside the scope of the current JTA transaction, it is the responsibility of the application to associate the entity manager with the transaction (if desired) by calling EntityManager.joinTransaction. If the entity manager is created outside the scope of a JTA transaction, it is not associated with the transaction unless EntityManager.joinTransaction is called.
Sharing of EntityManager Using CDI

As mentioned, if you want to share your EntityManager between components that constitutes one transaction, you should pass it manually (hey, after all it’s “application-managed”.) The CDI might be a solution here. You could produce the request scoped EntityManager and inject it into any component you need. It could look like this (in real-life you’d need to take care of disposal of EM as well):

public class Resources {    @PersistenceUnit    EntityManagerFactory emf;    @Produces @RequestScoped    public EntityManager createEntityManager() {        return emf.createEntityManager();    }}

Now in every bean we could have:

@Statelesspublic class MyBean {    @Inject    EntityManager em;}

It seems a very clean way of sharing the application-managed Persistence Context between different components that constitutes the transaction. However, the thing I feared was: knowing that the application-managed EntityManager transactionality behaviour depends on the location where it was created, such approach might sometimes give you nasty results. Take the following code as an example (it’s also available at my Github project, this class precisely here):

@Stateless@TransactionAttribute(TransactionAttributeType.NEVER)public class BeanABoundary {    @Inject    private EntityManager em;    @EJB    BeanB beanB;    public void invoke() {        em.getProperties();        beanB.invoke();}

Notice the BeanA being a non-transactional resource. Also note that we injected and invoked some operation on the EntityManager (this makes the injection to be actually performed.) Now if the BeanB is transactional and also injects and uses EntityManager – we’ll end with a non-transactional EntityManager that will not throw any exception and will not save any changes to the database.

In the case of old @PersistenceContext we’d be in a transaction because the EntityManager will be container-managed and the container would be aware of currently active transaction. The container is responsible for sharing the EntityManager between transaction boundaries. In case of shown CDI producer method, the CDI doesn’t know about running transaction and just share the EntityManager in anyway.

Of course, one may use the CDI and create a @Produces @PersistenceContext EntityManager em and then use @Inject EntityManager. This would work exactly as the @PersistenceContext EntityManager but allows us to define, e.g. a name of the persistence unit in a single place that produces the EntityManager. This, however, is not an option if we want to have an application-managed EntityManager.
 

Reference: Types of Entity Managers: Application-managed EntityManager from our JCG partner Piotr Nowicki at the Piotr Nowicki’s Homepage blog.


Source : feedproxy[dot]google[dot]com

No comments:

Post a Comment