mondayguy
mondayguy

Reputation: 991

Java EE transaction rollback

I have following ejb:

for (int i = 1; i <= shopItem.getQuantity(); i++) {
        purchase = new Purchase();
        purchase.setUser(user);
        // a lot of sets
        purchase.setPhoneNumber(order.getPhoneNumber());
        try {
            financeEntityEjb.createPurchase(purchase);
        } catch (NotEnoughFundsException e) {
       throw new NotEnoughFundsExceptionWithRollback(e); // Making in rollable
     }
  }

public void createPurchase(Purchase purchase) throws InputValidationException, NotEnoughFundsException {
    // a lot of calculations
    em.persist(purchase);
    em.flush();
    /* Closing Order */
            purchase.getOrder().setState(Order.State.PURCHASED);
            em.merge(purchase.getOrder());

    }

My Exception class:

@ApplicationException(rollback = true)
public class NotEnoughFundsExceptionWithRollback extends NotEnoughFundsException {
public NotEnoughFundsExceptionWithRollback() {
    }

    public NotEnoughFundsExceptionWithRollback(Throwable e) {
        super(e);
    }

    public NotEnoughFundsExceptionWithRollback(String message, Throwable e) {
        super(message, e);
    }
}

So I have problem that ejb rollbacks all em.persist(purchase); but ignores em.merge(purchase.getOrder());

UPD: Loop is in purchaseEjb. and CreatePurchase method is on financeEjb

Upvotes: 2

Views: 2125

Answers (1)

rapha&#235;λ
rapha&#235;λ

Reputation: 6523

I am assuming the code in the for-loop is not within the, or an, ejb (you are not using this). In that case most likely the problem is the following

Container managed transaction in EJB last a single method call. Depending on the transactional attributes it ignores, starts or joins a transaction. The default is required, which means the transaction starts on the call to createPurchase and ends when the method is finished (tipically a proxy takes care if this) .

The transaction is rolledback on a RuntimeException, when an application exception is throws with @ApplicationException(rollback = true) or when the set-rollback-only-flag has been set.

In your case most likely none of these happen within the transactional context of createPurchase. You did not show the code for NotEnoughFundsException, but i am assuming it is not annoted with @ApplicationException(rollback = true).

Instead you have annotated the NotEnoughFundsExceptionWithRollback, which is thrown outside of the transactional context by the client calling the EJB.

If you want the whole loop to be an atomic operation, you need to place that in an transactional context (e.g, using an EJB)

Upvotes: 2

Related Questions