需要在其范围结束之前强制保留容器管理的事务

Need to persist container managed transaction forcefully before its scope ends

我正在尝试使用 entityManager.flush()

在容器管理的事务范围结束之前保留它

bean class 被注解

@TransactionAttribute(TransactionAttributeType.REQUIRED)

通过这个 link: how we can get JPA EntityManager Flush work,我了解到使用 entityManager.flush() 不会提交事务。 DBMS 现在将知道此数据,但其他数据库会话将无法看到它。

我还尝试创建一个带注释的新 bean 方法

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

关注这个 link how to commit a transaction in EJB? 在范围在新 bean 方法内的其他事务中调用 entityManager.flush()。然而,这不起作用。

我正在寻找一种方法来强制提交事务以在数据库中保留其目前的状态。

类似于:

entityManager.getTransaction().commit();

这可以用于 BMT,但不能用于 CMT。

您可以封装将数据持久化到另一个 bean 中的逻辑,并用 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 注释它。调用此方法后,持久化数据应该可用。

更新版本
ContainerManagedTranaction (CMT) 示例

@TransactionAttribute(TransactionAttributeType.REQUIRED)    
public class OuterBean {
    @Inject
    PersistingBean bean;

    public void persistData() {
        Data data = loadExisitingData();
        update(data);
        update(data);

        bean.persistDataInOwnTransaction(data);

        externalCall();
    }
}

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)    
public class PersistingBean {
    @PersistenceContext
    EntityManager em;

    public void persistDataInOwnTransaction(Data data) {
        em.merge(data);
      }
}

BeanManagedTransaction (BMT) 示例
Oracles Java EE Tutorial

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class OuterBean {
    @Resource
    EJBContext context;
    @PersistenceContext
    EntityManager em;

    public void persistData() {
        UserTransaction ut = context.getUserTransaction();

        try {
            ut.begin();
            Data data1 = loadData1();
            update(data1);

            Data data2 = loadData2();
            update(data2);

            ut.commit();
        } catch(Exception ex) {
            ut.rollBack();
        }

        externalCall();
    }
}

终于找到了问题的解决方法。

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public class OuterBean {

@EJB
PersistingBean bean;
@PersistenceContext
EntityManager em;

public void persistData() {

    em.flush();

    procedureCall();

    Data data = loadExisitingData();
    update(data);
    update(data);

    bean.persistDataInOwnTransaction(data,em);

    em.refresh(getUpdatedEntity())

    externalCall();
}
}

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)   
 public class PersistingBean {

public void persistDataInOwnTransaction(Data data, EntityManager em) {
em.merge(data);
  }
}

注意:这里我们很幸运,我们有一个对 DB 的过程调用,因此 em.flush() 首先提交了版本 1 的事务,后来在使用递增的休眠版本 2 调用 em.merge(data) 时被覆盖。

em.merge(data) -> 在单独的事务中提交数据,因此实体将在它自己的事务中使用相同的 enityManager 在 persistDataInOwnTransaction(Data data, EntityManager em) 中作为参数传递的相同 enityManager 在数据库中更新,因此覆盖数据库中具有相同 em ID 的先前实体。

em.refresh(getUpdatedEntity()) -> 从数据库中刷新实例的状态,以便任何进一步的提交都可以发生在版本 3 的这个实体上,就像在我们的例子中,接近 bean 范围的末尾class。

因此最终不会在数据库中创建多条记录。每次我们尝试使用递增的休眠版本来持久化时,相同的实体都会被覆盖。