I got session bean which is managed by containter. Recently I run into problems, where exception is thrown:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
it is because some other process has updated row (and version field has changed). Now when it is thrown, I catch OptimisticLockException and want to re-run failed operation (and I want to put WRITE lock this time to be sure it won't fail again), I do it this way:
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);
}
and the methods I call in above:
@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();
}
Those 2 methods I have crated, because I was hoping the whole (parent) transaction will not fail because of exception thrown by flushRegisterTransactionUpdateAccountBalance().
Unfortunately it fails, when I call in catch block method retryBalanceUpdate, the first line of it's body (entityManager.refresh(ca)) throws:
[TxPolicy] javax.ejb.EJBTransactionRolledbackException: EntityManager must be access within a transaction [MyBean] No transaction javax.persistence.TransactionRequiredException: EntityManager must be access within a transaction
Does anybode know how I could achieve what I explained? I am using EJB 3.0, entityManager object is initiated by class-level annotation:
@PersistenceContext(unitName="MyPersistenceUnit") private EntityManager entityManager;
The class it self is stateless session bean with transaction attribute SUPPORTS