Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring JPA : Application managed persistence context with @Transactional and @PersistenceContext

Currently im trying out the application managed persistence context, by creating the entity manager manually and store them to enable transaction that spans multiple request calls (perhaps something like extended persistence context) in JSE application.

But, im wondering whether i can avoid sending the entityManager object throughout the service and DAO methods as an additional parameter by making use of the spring's @PersistenceContext injection and mark the methods with @Transactional annotation to use the transaction started manually with that entity manager.

I think i can somehow manage this by using a ThreadLocal for this feature, but i'll be happier to be able to attach this to the spring framework.

This is an example of What i have in mind :


The UI action method :

Here we can see the transaction is started by the ui logic, since there iss no facade / command method in the backend to group these callings to the business logic :

Long transactionid = tool.beginTransaction();

// calling business methods
tool.callBusinessLogic("purchase", "receiveGoods", 
                        paramObject1, transactionid);

tool.callBusinessLogic("inventory", "updateInventory", 
                        paramObject2, transactionid);

tool.commitTransaction(transactionid);

Inside the tool :

public Long beginTransaction() {
  // create the entity --> for the @PersistentContext
  Entitymanager entityManager = createEntityManagerFromFactory();
  long id = System.currentTimeMillis();
  entityManagerMap.put(id, entitymanager);

  // start the transaction --> for the @Transactional ?
  entityManager.getTransaction().begin();

  return id;
}

public void commitTransaction(Long transactionId) {
  EntityManager entityManager = entityManagerMap.get(transactionId);

  entityManager.getTransaction().commit();
}

public Object callBusinessLogic(String module, String function, 
                        Object paramObject, Long transactionid) {
    EntityManager em = entityManagerMap.get(transactionId);

    // =================================
    //        HOW TO DO THIS????
    // =================================
    putEntityManagerIntoCurrentPersistenceContext(em);

    return executeBusinessLogic(module, function, paramObject, transactionid);
}

And the example for the service method :

public class Inventory {
  // How can i get the entityManager that's been created by the tool for this thread ?
  @PersistenceContext
  private EntityManager entityManager;

  // How can i use the transaction with that transactionId ?
  @Transactional
  public void receiveGoods(Param param) {
    // ........
  }
}

Is there anyway to achieve this ?

Thank you !

like image 595
Albert Gan Avatar asked Feb 24 '11 06:02

Albert Gan


2 Answers

Spring's handling of the @PersistenceContext annotation does almost exactly what you're after, with one big difference: you always get a transaction scoped EntityManager and Spring injects always the same instance for the same thread, so you have kind of propagation and don't have to worry about thread-safety. But you'll never get an extended context this way!
Believe me, Spring 3 and extended persistence context don't play well together, maybe this will change in Spring 3.1 but I'm afraid that's not in their focus. If you want to use an extended persistence context let Spring inject the EntityManagerFactory (via @PersistenceUnit annotation) and then create the EntityManager on your own. For propagation you'll have to either pass the instance as a parameter or store it in a ThreadLocal yourself.

like image 51
Robin Avatar answered Oct 18 '22 19:10

Robin


Indeed to have a application managed persistence context, you need to somehow "hack" the @Transactional & @PersistenceContext infrastructure by providing them your own Entity Manager and do not let Spring create its own.

The key to achieve this is to play a little bit with the TransactionSynchronizationManager class to register your own Entity Manager to the thread local, Spring will use it to inject to the @PersistenceContext attribute.

I had this need some time ago for my own application and I've designed a small architecture based on Spring AOP to manage the extended persistence context.

Details here: JPA/Hibernate Global Conversation with Spring AOP

like image 25
doanduyhai Avatar answered Oct 18 '22 18:10

doanduyhai