HHH-9976 - JdbcResourceLocalTransactionCoordinatorImpl does not rollback on failure during #commit

This commit is contained in:
Steve Ebersole 2015-07-28 18:16:47 -05:00
parent 3d1a39f80d
commit 16c0a1f144
5 changed files with 42 additions and 19 deletions

View File

@ -21,6 +21,7 @@ import static org.hibernate.resource.transaction.TransactionCoordinator.Transact
/**
* @author Andrea Boriero
* @author Steve Ebersole
*/
public class TransactionImpl implements Transaction {
private static final Logger LOG = CoreLogging.logger( TransactionImpl.class );
@ -71,6 +72,13 @@ public class TransactionImpl implements Transaction {
@Override
public void rollback() {
TransactionStatus status = transactionDriverControl.getStatus();
if ( status == TransactionStatus.ROLLED_BACK || status == TransactionStatus.NOT_ACTIVE ) {
// Allow rollback() calls on completed transactions, just no-op.
LOG.debug( "rollback() called on an inactive transaction" );
invalidate();
return;
}
if ( !status.canRollback() ) {
throw new TransactionException( "Cannot rollback transaction in current status [" + status.name() + "]" );
}

View File

@ -222,19 +222,35 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
@Override
public void commit() {
if ( rollbackOnly ) {
throw new TransactionException( "Transaction was marked for rollback only; cannot commit" );
}
try {
if ( rollbackOnly ) {
throw new TransactionException( "Transaction was marked for rollback only; cannot commit" );
}
JdbcResourceLocalTransactionCoordinatorImpl.this.beforeCompletionCallback();
jdbcResourceTransaction.commit();
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( true );
JdbcResourceLocalTransactionCoordinatorImpl.this.beforeCompletionCallback();
jdbcResourceTransaction.commit();
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( true );
}
catch (RuntimeException e) {
try {
rollback();
}
catch (RuntimeException e2) {
log.debug( "Encountered failure rolling back failed commit", e2 );;
}
throw e;
}
}
@Override
public void rollback() {
jdbcResourceTransaction.rollback();
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( false );
if ( rollbackOnly || getStatus() == TransactionStatus.ACTIVE ) {
rollbackOnly = false;
jdbcResourceTransaction.rollback();
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( false );
}
// no-op otherwise.
}
@Override

View File

@ -106,7 +106,7 @@ public class SynchronizationRegistryStandardImplTests {
// exception in beforeCompletion
registry.clearSynchronizations();
registry = new SynchronizationRegistryStandardImpl();
synchronization = new SynchronizationErrorImpl( false, true );
synchronization = SynchronizationErrorImpl.forAfter();
registry.registerSynchronization( synchronization );
try {
registry.notifySynchronizationsAfterTransactionCompletion( Status.STATUS_COMMITTED );

View File

@ -88,14 +88,13 @@ public class BasicJdbcTransactionTests {
catch (TransactionException expected) {
}
finally {
assertEquals( TransactionStatus.MARKED_ROLLBACK, transactionCoordinator.getTransactionDriverControl().getStatus() );
transactionCoordinator.getTransactionDriverControl().rollback();
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
}
}
@Test
@SuppressWarnings("EmptyCatchBlock")
public void testSynchronizationFailureMarksTransactionForRollbackOnly() {
public void testSynchronizationFailure() {
final TransactionCoordinatorOwnerTestingImpl owner = new TransactionCoordinatorOwnerTestingImpl();
final JdbcResourceLocalTransactionCoordinatorBuilderImpl transactionCoordinatorBuilder =
new JdbcResourceLocalTransactionCoordinatorBuilderImpl();
@ -122,8 +121,10 @@ public class BasicJdbcTransactionTests {
catch (Exception expected) {
}
finally {
assertEquals( TransactionStatus.MARKED_ROLLBACK, transactionCoordinator.getTransactionDriverControl().getStatus() );
transactionCoordinator.getTransactionDriverControl().rollback();
assertEquals(
TransactionStatus.NOT_ACTIVE,
transactionCoordinator.getTransactionDriverControl().getStatus()
);
}
}
}

View File

@ -401,14 +401,13 @@ public abstract class AbstractBasicJtaTestScenarios {
catch (TransactionException expected) {
}
finally {
assertEquals( TransactionStatus.MARKED_ROLLBACK, transactionCoordinator.getTransactionDriverControl().getStatus() );
transactionCoordinator.getTransactionDriverControl().rollback();
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
}
}
@Test
@SuppressWarnings("EmptyCatchBlock")
public void testSynchronizationFailureMarksTransactionForRollbackOnly() throws Exception {
public void testSynchronizationFailure() throws Exception {
JtaTransactionCoordinatorImpl transactionCoordinator = new JtaTransactionCoordinatorImpl(
transactionCoordinatorBuilder,
owner,
@ -434,8 +433,7 @@ public abstract class AbstractBasicJtaTestScenarios {
catch (Exception expected) {
}
finally {
assertEquals( TransactionStatus.MARKED_ROLLBACK, transactionCoordinator.getTransactionDriverControl().getStatus() );
transactionCoordinator.getTransactionDriverControl().rollback();
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
}
}
}