我得到了由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答案 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());
}
}