【问题标题】:Spring JPA : Application managed persistence context with @Transactional and @PersistenceContextSpring JPA:使用@Transactional 和@PersistenceContext 的应用程序管理的持久性上下文
【发布时间】:2011-07-03 08:26:24
【问题描述】:

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

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

我想我可以通过为这个特性使用 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) {
    // ........
  }
}

有没有办法做到这一点?

谢谢!

【问题讨论】:

    标签: spring jpa jpa-2.0


    【解决方案1】:

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

    【讨论】:

    • 手动创建EntityManager和使用@PersistenceContext注入有什么区别。每次我调用entityManagerFactory.createEntityManager() 时是否会获得不同的实体管理器对象,或者只是使用@PersistenceContext 注入的共享实体管理器
    • entityManagerFactory.createEntityManager() 创建一个新的 application-managed 实例,而@PersistenceContext 注入一个 container-managed 实例。检查 JPA 规范以了解差异。在 Spring 框架的特定情况下,容器管理的实例具有事务范围并绑定到本地线程,因此每个线程最多同时具有一个实例。 (所以不需要同步)
    【解决方案2】:

    确实有一个应用程序管理的持久性上下文,您需要以某种方式“破解”@Transactional@PersistenceContext 基础架构,提供您自己的 strong> Entity Manager,不要让 Spring 创建自己的。

    实现这一点的关键是使用 TransactionSynchronizationManager 类将自己的实体管理器注册到线程本地,Spring 将使用它注入到 @PersistenceContext 属性。

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

    详情请看:JPA/Hibernate Global Conversation with Spring AOP

    【讨论】:

    • 虽然我目前不再需要这个功能,但我会在将来再次需要它时尝试一下。谢谢!
    【解决方案3】:

    当您通过@Transactional 配置事务时,您应该将事务的配置移交给注解。
    在这里您开始您的事务,然后希望@Transactional 也将被触发。
    有关更多信息,您最好开始阅读http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html => 9.5.6。使用@Transactional

    【讨论】:

      猜你喜欢
      • 2017-12-15
      • 1970-01-01
      • 2013-09-24
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      • 2020-03-18
      • 2013-10-31
      • 2015-01-13
      相关资源
      最近更新 更多