0

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

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

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

[TxPolicy] javax.ejb.EJBTransactionRolledbackException:EntityManager 必须在事务内访问 [MyBean] 无事务 javax.persistence.TransactionRequiredException:EntityManager 必须在事务内访问

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

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

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

4

1 回答 1

0

乐观锁异常:

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

您可以使用 annotation 创建自定义异常@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());
} 
}
于 2013-10-16T09:41:26.997 回答