Introduce TransactionExecutionListener with begin/commit/rollback notifications
Includes ConfigurableTransactionManager interface for listener registration. Includes additional introspection methods on TransactionExecution interface. Includes default method declarations on TransactionStatus/SmartTransactionObject. Closes gh-27479
This commit is contained in:
@@ -88,8 +88,7 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock)
|
||||
.flatMap(connection -> TransactionSynchronizationManager.forCurrentTransaction()
|
||||
.doOnNext(synchronizationManager -> synchronizationManager.registerSynchronization(
|
||||
sync)))
|
||||
.doOnNext(synchronizationManager -> synchronizationManager.registerSynchronization(sync)))
|
||||
.as(operator::transactional)
|
||||
.as(StepVerifier::create)
|
||||
.expectNextCount(1)
|
||||
@@ -120,12 +119,11 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock).as(
|
||||
operator::transactional)
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock)
|
||||
.as(operator::transactional)
|
||||
.as(StepVerifier::create)
|
||||
.expectErrorSatisfies(actual -> assertThat(actual).isInstanceOf(
|
||||
CannotCreateTransactionException.class).hasCauseInstanceOf(
|
||||
R2dbcBadGrammarException.class))
|
||||
CannotCreateTransactionException.class).hasCauseInstanceOf(R2dbcBadGrammarException.class))
|
||||
.verify();
|
||||
}
|
||||
|
||||
@@ -140,12 +138,16 @@ class R2dbcTransactionManagerUnitTests {
|
||||
definition.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock).as(
|
||||
operator::transactional)
|
||||
.as(StepVerifier::create)
|
||||
.expectNextCount(1)
|
||||
.verifyComplete();
|
||||
operator.execute(tx -> {
|
||||
assertThat(tx.getTransactionName()).isEqualTo("my-transaction");
|
||||
assertThat(tx.hasTransaction()).isTrue();
|
||||
assertThat(tx.isNewTransaction()).isTrue();
|
||||
assertThat(tx.isNested()).isFalse();
|
||||
assertThat(tx.isReadOnly()).isTrue();
|
||||
assertThat(tx.isRollbackOnly()).isFalse();
|
||||
assertThat(tx.isCompleted()).isFalse();
|
||||
return Mono.empty();
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
ArgumentCaptor<io.r2dbc.spi.TransactionDefinition> txCaptor = ArgumentCaptor.forClass(io.r2dbc.spi.TransactionDefinition.class);
|
||||
verify(connectionMock).beginTransaction(txCaptor.capture());
|
||||
@@ -171,8 +173,8 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock).as(
|
||||
operator::transactional)
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock)
|
||||
.as(operator::transactional)
|
||||
.as(StepVerifier::create)
|
||||
.expectNextCount(1)
|
||||
.verifyComplete();
|
||||
@@ -190,8 +192,8 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock).as(
|
||||
operator::transactional)
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock)
|
||||
.as(operator::transactional)
|
||||
.as(StepVerifier::create)
|
||||
.expectNextCount(1)
|
||||
.verifyComplete();
|
||||
@@ -215,8 +217,8 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock).as(
|
||||
operator::transactional)
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock)
|
||||
.as(operator::transactional)
|
||||
.as(StepVerifier::create)
|
||||
.expectNextCount(1)
|
||||
.verifyComplete();
|
||||
@@ -262,11 +264,9 @@ class R2dbcTransactionManagerUnitTests {
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm);
|
||||
|
||||
ConnectionFactoryUtils.getConnection(connectionFactoryMock)
|
||||
.doOnNext(connection -> {
|
||||
throw new IllegalStateException();
|
||||
}).as(operator::transactional)
|
||||
.as(StepVerifier::create)
|
||||
.verifyError(IllegalStateException.class);
|
||||
.doOnNext(connection -> { throw new IllegalStateException(); })
|
||||
.as(operator::transactional)
|
||||
.as(StepVerifier::create).verifyError(IllegalStateException.class);
|
||||
|
||||
assertThat(commits).hasValue(0);
|
||||
assertThat(rollbacks).hasValue(1);
|
||||
@@ -286,8 +286,7 @@ class R2dbcTransactionManagerUnitTests {
|
||||
reactiveTransaction.setRollbackOnly();
|
||||
return ConnectionFactoryUtils.getConnection(connectionFactoryMock)
|
||||
.doOnNext(connection -> connection.createStatement("foo")).then();
|
||||
}).as(StepVerifier::create)
|
||||
.verifyError(BadSqlGrammarException.class);
|
||||
}).as(StepVerifier::create).verifyError(BadSqlGrammarException.class);
|
||||
|
||||
verify(connectionMock).beginTransaction(any(io.r2dbc.spi.TransactionDefinition.class));
|
||||
verify(connectionMock).createStatement("foo");
|
||||
@@ -308,7 +307,7 @@ class R2dbcTransactionManagerUnitTests {
|
||||
.doOnNext(connection -> {
|
||||
throw new IllegalStateException("Intentional error to trigger rollback");
|
||||
}).then()).as(StepVerifier::create)
|
||||
.verifyErrorSatisfies(e -> assertThat(e)
|
||||
.verifyErrorSatisfies(ex -> assertThat(ex)
|
||||
.isInstanceOf(BadSqlGrammarException.class)
|
||||
.hasCause(new R2dbcBadGrammarException("Rollback should fail"))
|
||||
);
|
||||
@@ -327,15 +326,21 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm);
|
||||
operator.execute(tx -> {
|
||||
tx.setRollbackOnly();
|
||||
assertThat(tx.getTransactionName()).isEmpty();
|
||||
assertThat(tx.hasTransaction()).isTrue();
|
||||
assertThat(tx.isNewTransaction()).isTrue();
|
||||
assertThat(tx.isNested()).isFalse();
|
||||
assertThat(tx.isReadOnly()).isFalse();
|
||||
assertThat(tx.isRollbackOnly()).isFalse();
|
||||
tx.setRollbackOnly();
|
||||
assertThat(tx.isRollbackOnly()).isTrue();
|
||||
assertThat(tx.isCompleted()).isFalse();
|
||||
return TransactionSynchronizationManager.forCurrentTransaction().doOnNext(
|
||||
synchronizationManager -> {
|
||||
assertThat(synchronizationManager.hasResource(connectionFactoryMock)).isTrue();
|
||||
synchronizationManager.registerSynchronization(sync);
|
||||
}).then();
|
||||
}).as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(connectionMock).beginTransaction(any(io.r2dbc.spi.TransactionDefinition.class));
|
||||
verify(connectionMock).rollbackTransaction();
|
||||
@@ -357,14 +362,19 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
operator.execute(tx1 -> {
|
||||
assertThat(tx1.getTransactionName()).isEmpty();
|
||||
assertThat(tx1.hasTransaction()).isTrue();
|
||||
assertThat(tx1.isNewTransaction()).isTrue();
|
||||
assertThat(tx1.isNested()).isFalse();
|
||||
assertThat(tx1.isReadOnly()).isFalse();
|
||||
assertThat(tx1.isRollbackOnly()).isFalse();
|
||||
assertThat(tx1.isCompleted()).isFalse();
|
||||
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER);
|
||||
return operator.execute(tx2 -> {
|
||||
fail("Should have thrown IllegalTransactionStateException");
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create)
|
||||
.verifyError(IllegalTransactionStateException.class);
|
||||
}).as(StepVerifier::create).verifyError(IllegalTransactionStateException.class);
|
||||
|
||||
verify(connectionMock).rollbackTransaction();
|
||||
verify(connectionMock).close();
|
||||
@@ -381,14 +391,17 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
operator.execute(tx1 -> {
|
||||
assertThat(tx1.isNewTransaction()).isTrue();
|
||||
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
return operator.execute(tx2 -> {
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
assertThat(tx1.hasTransaction()).isTrue();
|
||||
assertThat(tx1.isNewTransaction()).isTrue();
|
||||
assertThat(tx1.isNested()).isFalse();
|
||||
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
return operator.execute(tx2 -> {
|
||||
assertThat(tx2.hasTransaction()).isTrue();
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
assertThat(tx2.isNested()).isTrue();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(connectionMock).createSavepoint("SAVEPOINT_1");
|
||||
verify(connectionMock).releaseSavepoint("SAVEPOINT_1");
|
||||
@@ -407,15 +420,20 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
operator.execute(tx1 -> {
|
||||
assertThat(tx1.isNewTransaction()).isTrue();
|
||||
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
return operator.execute(tx2 -> {
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
tx2.setRollbackOnly();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
assertThat(tx1.hasTransaction()).isTrue();
|
||||
assertThat(tx1.isNewTransaction()).isTrue();
|
||||
assertThat(tx1.isNested()).isFalse();
|
||||
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
return operator.execute(tx2 -> {
|
||||
assertThat(tx2.hasTransaction()).isTrue();
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
assertThat(tx2.isNested()).isTrue();
|
||||
assertThat(tx2.isRollbackOnly()).isFalse();
|
||||
tx2.setRollbackOnly();
|
||||
assertThat(tx2.isRollbackOnly()).isTrue();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(connectionMock).createSavepoint("SAVEPOINT_1");
|
||||
verify(connectionMock).rollbackTransactionToSavepoint("SAVEPOINT_1");
|
||||
@@ -432,16 +450,19 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
operator.execute(tx1 -> {
|
||||
assertThat(tx1.isNewTransaction()).isFalse();
|
||||
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
|
||||
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
TransactionalOperator inner = TransactionalOperator.create(tm, innerDef);
|
||||
return inner.execute(tx2 -> {
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
assertThat(tx1.hasTransaction()).isFalse();
|
||||
assertThat(tx1.isNewTransaction()).isFalse();
|
||||
assertThat(tx1.isNested()).isFalse();
|
||||
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
|
||||
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
TransactionalOperator inner = TransactionalOperator.create(tm, innerDef);
|
||||
return inner.execute(tx2 -> {
|
||||
assertThat(tx2.hasTransaction()).isTrue();
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
assertThat(tx2.isNested()).isFalse();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(connectionMock).commitTransaction();
|
||||
verify(connectionMock).close();
|
||||
@@ -456,17 +477,22 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
operator.execute(tx1 -> {
|
||||
assertThat(tx1.isNewTransaction()).isFalse();
|
||||
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
|
||||
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
TransactionalOperator inner = TransactionalOperator.create(tm, innerDef);
|
||||
return inner.execute(tx2 -> {
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
tx2.setRollbackOnly();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
assertThat(tx1.hasTransaction()).isFalse();
|
||||
assertThat(tx1.isNewTransaction()).isFalse();
|
||||
assertThat(tx1.isNested()).isFalse();
|
||||
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
|
||||
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
|
||||
TransactionalOperator inner = TransactionalOperator.create(tm, innerDef);
|
||||
return inner.execute(tx2 -> {
|
||||
assertThat(tx2.hasTransaction()).isTrue();
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
assertThat(tx2.isNested()).isFalse();
|
||||
assertThat(tx2.isRollbackOnly()).isFalse();
|
||||
tx2.setRollbackOnly();
|
||||
assertThat(tx2.isRollbackOnly()).isTrue();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(connectionMock).rollbackTransaction();
|
||||
verify(connectionMock).close();
|
||||
@@ -481,16 +507,19 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
operator.execute(tx1 -> {
|
||||
assertThat(tx1.hasTransaction()).isFalse();
|
||||
assertThat(tx1.isNewTransaction()).isFalse();
|
||||
assertThat(tx1.isNested()).isFalse();
|
||||
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
|
||||
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
TransactionalOperator inner = TransactionalOperator.create(tm, innerDef);
|
||||
return inner.execute(tx2 -> {
|
||||
assertThat(tx2.hasTransaction()).isTrue();
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
assertThat(tx2.isNested()).isFalse();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(connectionMock).commitTransaction();
|
||||
verify(connectionMock).close();
|
||||
@@ -505,17 +534,22 @@ class R2dbcTransactionManagerUnitTests {
|
||||
|
||||
TransactionalOperator operator = TransactionalOperator.create(tm, definition);
|
||||
operator.execute(tx1 -> {
|
||||
assertThat(tx1.isNewTransaction()).isFalse();
|
||||
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
|
||||
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
TransactionalOperator inner = TransactionalOperator.create(tm, innerDef);
|
||||
return inner.execute(tx2 -> {
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
tx2.setRollbackOnly();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
assertThat(tx1.hasTransaction()).isFalse();
|
||||
assertThat(tx1.isNewTransaction()).isFalse();
|
||||
assertThat(tx1.isNested()).isFalse();
|
||||
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
|
||||
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
TransactionalOperator inner = TransactionalOperator.create(tm, innerDef);
|
||||
return inner.execute(tx2 -> {
|
||||
assertThat(tx2.hasTransaction()).isTrue();
|
||||
assertThat(tx2.isNewTransaction()).isTrue();
|
||||
assertThat(tx2.isNested()).isFalse();
|
||||
assertThat(tx2.isRollbackOnly()).isFalse();
|
||||
tx2.setRollbackOnly();
|
||||
assertThat(tx2.isRollbackOnly()).isTrue();
|
||||
return Mono.empty();
|
||||
});
|
||||
}).as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(connectionMock).rollbackTransaction();
|
||||
verify(connectionMock).close();
|
||||
|
||||
Reference in New Issue
Block a user