Spring JPA:使用@Transactional和@PersistenceContext的应用程序管理持久化上下文

时间:2011-02-24 06:58:19

标签: spring jpa jpa-2.0

目前我正在尝试应用程序管理的持久化上下文,通过手动创建实体管理器并将它们存储起来,以便在JSE应用程序中启用跨越多个请求调用的事务(可能类似于扩展持久性上下文)。

但是,我想知道我是否可以通过使用spring的@PersistenceContext注入来避免在整个服务和DAO方法中发送entityManager对象作为附加参数,并使用@Transactional注释标记方法以使用手动启动的事务实体经理。

我想我可以通过使用ThreadLocal来管理这个功能,但是我能更高兴能够将它附加到spring框架。

这是我想到的一个例子:


UI动作方法:

这里我们可以看到事务是由ui逻辑启动的,因为后端没有外观/命令方法将这些调用分组到业务逻辑:

Long transactionid = tool.beginTransaction();

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

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

tool.commitTransaction(transactionid);

工具内部:

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);
}

服务方法的例子:

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) {
    // ........
  }
}

无论如何要实现这个目标吗?

谢谢!

3 个答案:

答案 0 :(得分:9)

Spring对@PersistenceContext注释的处理确实几乎正是你所追求的,但有一个很大的不同:你总是得到一个事务范围的EntityManager和Spring总是注入相同的实例相同的线程,所以你有一种传播,不必担心线程安全。但是你永远不会以这种方式得到扩展的背景! 相信我,Spring 3和扩展的持久化环境不能很好地结合在一起,也许这会在Spring 3.1中发生变化,但我担心这不是他们关注的焦点。如果要使用扩展持久化上下文,让Spring注入EntityManagerFactory(通过@PersistenceUnit注释),然后自己创建EntityManager。对于传播,您必须将实例作为参数传递或自己将其存储在ThreadLocal中。

答案 1 :(得分:3)

确实有一个应用程序管理持久化上下文,你需要以某种方式“破解” @Transactional & @PersistenceContext 基础架构,为他们提供自己的实体管理器,不要让Spring创建自己的实体。

实现这一目标的关键是使用 TransactionSynchronizationManager 类进行一点注册,将自己的实体管理器注册到本地线程,Spring将使用它注入 @PersistenceContext < / strong> attribute。

前段时间我对自己的应用程序有这种需求,并且我设计了一个基于Spring AOP的小型架构来管理扩展的持久化上下文。

详细信息:JPA/Hibernate Global Conversation with Spring AOP

答案 2 :(得分:0)

当您通过@Transactional配置交易时,您应该将交易配置移交给注释。
在这里,您开始交易,然后希望@Transactional也会被触发 有关详细信息,您最好开始阅读http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html =&gt; 9.5.6。使用@Transactional