Pre Java EE 7 alternative to JPA 2.1 unsynchronized persistence context
Unsynchronized persistence context in Java EE 7
JPA 2.1 introduced the concept of unsynchronized persistence context which allows fine grained control over flushing of the JPA Entity Manager i.e. by explicitly calling EntityManager#joinTransaction. Previously, this was defaulted to end of JTA transaction e.g. in a typical Stateless EJB, the entity manager would flush its state to the DB at the end of a method (which starts and ends a transaction by default). You can read more about this, here and here.
Possible in the pre Java EE 7 era as well (both EE 5 and EE 6)
Java EE 5 and 6 have can be tweaked to achieve the same result as attained by the Unsynchronized Persistence Context in Java EE 7
Imagine a use case where customer details are being edited in a sequential manner (using a wizard like flow) e.g. address info in screen 1, contact info in screen 2 etc. You would want to save the state of the each category as and when the customer enters is but do not wish to push the entire state to the DB until the process is complete i.e. info for all the categories is entered by the user
package com.abhirockzz.conversationalee; import com.abhirockzz.conversationalee.entity.Customer; import java.util.Date; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.Remove; import javax.ejb.Stateful; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContextType; @Stateful @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public class CustomerEditorFacade{ @PersistenceContext(type = PersistenceContextType.EXTENDED) EntityManager em; @Inject //this won't work in Java EE 5 Principal authenticatedUser; private Customer customer; @PostConstruct public void init(){ System.out.println("CustomerEditorFacade created at " + new Date().toString()); } @PreDestroy public void destroy(){ System.out.println("CustomerEditorFacade destroyed at " + new Date().toString()); } //step 1 public void updateCity(String custID, String city){ String custID = authenticatedUser.getName(); //assume we have an authenticated principal which is the same as the customer ID in the Database Customer customerFromDB = em.find(Customer.class, Integer.valueOf(custID)); //obtain a 'managed' entity customerFromDB.setCity(city); //no need to call em.persist customer = customerFromDB; //just switch references //Customer state will NOT be pushed to DB } //step 2 public void updateEmail(String email){ customer.setEmail(email); //not pushed to DB yet } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void save(){ //dummy method to trigger transaction and flush EM state to DB } @Remove public void finish(){ //optional method to provide a way to evict this bean once used //not required if this is session scoped } }
The code comments are self explanatory (hopefully)
Cheers!
Reference: | Pre Java EE 7 alternative to JPA 2.1 unsynchronized persistence context from our JCG partner Abhishek Gupta at the Object Oriented.. blog. |