EJB:CMT,抛出异常后如何重试操作

时间:2013-10-11 13:58:25

标签: java hibernate transactions ejb ejb-3.0

我得到了由containter管理的会话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();
}

我创建的那两个方法,因为我希望整个(父)事务不会因为flushRegisterTransactionUpdountAccountBalance()抛出的异常而失败。

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

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

anybode是否知道如何实现我的解释?我使用EJB 3.0,entityManager对象由类级注释启动:

@PersistenceContext(unitName =“MyPersistenceUnit”)私有EntityManager entityManager;

它自己的类是具有事务属性SUPPORTS

的无状态会话bean

1 个答案:

答案 0 :(得分:0)

  

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