【问题标题】:EJB: CMT, how to retry operation after expeption thrownEJB:CMT,抛出异常后如何重试操作
【发布时间】:2013-10-11 13:58:24
【问题描述】:

我得到了由容器管理的会话 bean。最近遇到问题,抛出异常:

org.hibernate.StaleObjectStateException: 行被另一个事务更新或删除(或未保存值映射不正确)

这是因为某些其他进程已更新行(并且版本字段已更改)。现在,当它被抛出时,我捕获了 OptimisticLockException 并想重新运行失败的操作(这次我想放置 WRITE 锁以确保它不会再次失败),我这样做:

T ctj = new T();
C ca = entityManager.find(C.class, id);     
Double newBalance = Operations.add(ca.getAccountBalance(), amount);
ca.setAccountBalance(newBalance);
entityManager.persist(ca);
ctj.setBalanceAfterTransaction(newBalance);    
entityManager.persist(ctj);
try {
    flushRegisterTransactionUpdateAccountBalance();
} catch(OptimisticLockException ex) {
    retryBalanceUpdate(ca, ctj, amount);
}    

以及我上面调用的方法:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private void retryBalanceUpdate(C ca, T ctj, Double amount) {
    entityManager.refresh(ca);
entityManager.lock(ca, LockModeType.WRITE);
    Double newBalance = Operations.add(ca.getAccountBalance(), amount);
    ca.setAccountBalance(newBalance);
    entityManager.persist(ca);      
    ctj.setBalanceAfterTransaction(newBalance);
    entityManager.persist(ctj);
    flushRegisterTransactionUpdateAccountBalance();    
}

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private void flushRegisterTransactionUpdateAccountBalance() {
    entityManager.flush();
}

我已经创建了这 2 个方法,因为我希望整个(父)事务不会因为 flushRegisterTransactionUpdateAccountBalance() 引发的异常而失败。

不幸的是它失败了,当我调用 catch 块方法 retryBalanceUpdate 时,它​​的主体 (entityManager.refresh(ca)) 的第一行抛出:

[TxPolicy] javax.ejb.EJBTransactionRolledbackException: EntityManager 必须在事务中访问 [MyBean] 没有交易 javax.persistence.TransactionRequiredException: EntityManager 必须在事务中访问

有没有人知道我怎样才能实现我所解释的?我使用的是 EJB 3.0,entityManager 对象是由类级注解发起的:

@PersistenceContext(unitName="MyPersistenceUnit") private EntityManager entityManager;

它自己的类是具有事务属性SUPPORTS的无状态会话bean

【问题讨论】:

    标签: java hibernate transactions ejb ejb-3.0


    【解决方案1】:

    OptimisticLockException:

    在发生乐观锁定冲突时由持久性提供程序抛出。这个异常可能被抛出为 API 调用、刷新或提交时的一部分。 当前 事务,如果一个处于活动状态,将被标记为回滚

    您可以使用注释@ApplicationException(rollback=false) 创建自定义异常。在 flushRegisterTransactionUpdateAccountBalance 中,您必须捕获 OptimisticLockException 并重新抛出自定义异常。

    可以参考下面的示例代码。

    try {
        flushRegisterTransactionUpdateAccountBalance();
    } catch(XApplicationException ex) {
        retryBalanceUpdate(ca, ctj, amount);
    } 
    

    在下面的代码中,处理异常然后重新抛出标记为rollback = false的自定义异常。

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    private void flushRegisterTransactionUpdateAccountBalance() throws XApplicationException{
        try {
        entityManager.flush();
        } catch(OptimisticLockException ex) {
         throw new XApplicationException(ex.getMessage());
    } 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-29
      • 1970-01-01
      • 2020-06-22
      相关资源
      最近更新 更多