Saturday, April 4, 2009

Extended Persistence Context

Extended persistence context is an interesting feature of the JPA specification. It allows one to declare that the injected EntityManager lives beyond the scope of the JTA transaction, that is, to extend it to the lifetime of the stateful session bean itself. This is achieved with the following annotation:
@PersistenceContext(type=PersistenceContextType.EXTENDED) EntityManager em;

Doing this has a couple of implications.
First of all, within the extended persistence context, managed entities remain managed even after the transaction commits (or is rolled back). This behavior is very different than that of a transaction scoped context, were entities get detached at the end of the transaction.
Second implication important to note is that changes done to the managed entities from outside of a transaction will not be propagated to the database immediately, and will be buffered instead. In order to get the changes reflected in the database, the EntitiyManager needs to be accessed from a transaction context and flushed (by invoking it's flush() method).

For obvious reasons, extended persistence context is only available within stateful Session Beans.

The most frequently quoted example of use is a multi-step conversation with a client, where the data that is to be persisted in a single transaction is acquired form a client in a series of steps with arbitrary periods of time in between. In this scenario, changes are sequentially applied to the managed entity in question, and the EntityManager is flushed at the very end of the conversation.

To illustrate this, image you were dealing with a multi-page client registration form. On each page, the client is expected to input some information about themselves, but each time the information pertains to a different aspect. For example, the first page could ask for general details, like name and title, the second would deal with the contact info, and the third could ask for some optional data, like an average income or a favorite hobby.
Now, to achieve this, you could create a stateful bean similar to the following:
@Stateful
public class RegistrationBean implements Registration
{
@PersistenceContext(type=PersistenceContextType.EXTENDED) EntityManager em;

private Customer customer;

public long createCustomer(String name, String lastName)
{
customer = new Customer();
customer.setName(name);
customer.setLastName(lastName);
em.persist(customer);
return customer.getId();
}

public void setContacts(String address, String phoneNumber, String email)
{
customer.setAddress(address);
customer.setPhoneNumber(phoneNumber);
customer.setEmail(email);
}

public void setOptionals(...)
{
...
}

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void confirmRegistration() {
em.flush();
}
}

In conclusion, it's worth to note that the same effect could have been achieved by wrapping the whole conversation in a single user-managed transaction, but that it still makes more sense to exploit the power of an extended persistence context as it provides both a simpler and cleaner solution.

4 comments:

  1. Good article. I wrote something similar, I explain here:

    http://azajava.blogspot.com/2009/09/introduction-i-decided-to-share-special.html

    Regards

    ReplyDelete
  2. Very good article,
    BTW, how do you displaying the code under blogspot that way ?

    ReplyDelete
  3. I don't know if there's a good way to see when someone comments... that's why I don't notice a question for months. So sorry.
    If it still counts, I am thankful for your kind words.
    Regarding code formatting, I am using a publicly available JS library called SyntaxHighlighter. You can find it here http://code.google.com/p/syntaxhighlighter/.
    If you need to, you can check the source for this page as well, it will give some hint too.

    ReplyDelete
  4. Thanks, nice post.

    ReplyDelete