Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate 5 and Transaction rollback detection with interceptor

We had a Hibernate Interceptor that was intercepting afterTransactionCommit and checking the Transaction for wasCommited(), but we recently upgraded to Hibernate 5.0.7.Final, and hibernate 5 no longer has this call, and when we call the getStatus() function we only every seem to get either ACTIVE or NOT_ACTIVE regardless of the transaction state.

I looked at afterTransactionBegin and the transaction is marked ACTIVE, which is expected, and in beforeTransactionCompletion it is still marked ACTIVE, which again, is expected, but then in afterTransactionCommit it is marked NOT_ACTIVE, which doesn't make a sense to me. I would have expected one of COMMITTED, ROLLED_BACK, FAILED_COMMIT. I get this no matter if the transaction state, even if I throw an exception which causes a rollback, I still don't see any status other than NOT_ACTIVE.

The reason we are looking for this information is to determine if we need to post some messages to a queue. Basically if the transaction wasn't committed don't post. As of right now with Hibernate 5 I can't seem to find out how to determine programatically if the transaction was successful or not.

like image 972
Zipper Avatar asked Feb 24 '16 20:02

Zipper


3 Answers

Hibernate 5 removed the ability to detect rollback in it's interceptor. Instead one can capture that transaction was rolled back and infer a rollback if it was not committed.

For example:

public class MyInterceptor extends EmptyInterceptor {
.
.
.

private static ThreadLocal<Boolean> wasCommited = new ThreadLocal();

@Override
public void beforeTransactionCompletion(Transaction tx) {
    // not called for rollback
    wasCommited.set(Boolean.TRUE);
}


@Override
public void afterTransactionCompletion(Transaction tx) {

    if ( !Boolean.TRUE.equals(wasCommited.get()) ) {
        try {
           // handle transaction rolled back
        }
        finally {
            wasCommited.set(null);
        }
    }
}
}
like image 53
Tim Dugan Avatar answered Nov 12 '22 15:11

Tim Dugan


If you use Spring transaction, you can use a TransactionSynchronization for this kind of things. For example :

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
           void afterCommit() {
                ..
           }
});

See TransactionSynchronizationManager

like image 2
Jérémie B Avatar answered Nov 12 '22 15:11

Jérémie B


I successfully utilized javax.transaction.Synchronization which can be registered with the transaction and receives correct status. It can be registered using the Hibernate Interceptor:

  @Override
  public void afterTransactionBegin(Transaction tx) {
    tx.registerSynchronization(new Synchronization() {
      @Override
      public void afterCompletion(int status) {
        // Here the status is correct
      }
    });
  }

Edit:

Unfortunattely, this solution works only, if the commit or rollback succeedes, otherwise the callback is not called. I must have had wrong test initially. You can see that in the code of JdbcResourceLocalTransactionCoordinatorImpl.TransactionDriverControlImpl.

like image 1
vnov Avatar answered Nov 12 '22 17:11

vnov