use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class AbstractReactiveTransactionAspectTests method twoTransactionsShouldSucceed.
/**
* Check that two transactions are created and committed.
*/
@Test
public void twoTransactionsShouldSucceed() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas1 = new MapTransactionAttributeSource();
tas1.register(getNameMethod, txatt);
MapTransactionAttributeSource tas2 = new MapTransactionAttributeSource();
tas2.register(setNameMethod, txatt);
ReactiveTransaction status = mock(ReactiveTransaction.class);
ReactiveTransactionManager rtm = mock(ReactiveTransactionManager.class);
// expect a transaction
given(rtm.getReactiveTransaction(txatt)).willReturn(Mono.just(status));
given(rtm.commit(status)).willReturn(Mono.empty());
DefaultTestBean tb = new DefaultTestBean();
TestBean itb = (TestBean) advised(tb, rtm, new TransactionAttributeSource[] { tas1, tas2 });
itb.getName().as(StepVerifier::create).verifyComplete();
Mono.from(itb.setName("myName")).as(StepVerifier::create).verifyComplete();
verify(rtm, times(2)).commit(status);
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class ReactiveTransactionSupportTests method noExistingTransaction.
@Test
public void noExistingTransaction() {
ReactiveTransactionManager tm = new ReactiveTestTransactionManager(false, true);
tm.getReactiveTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_SUPPORTS)).contextWrite(TransactionContextManager.createTransactionContext()).cast(GenericReactiveTransaction.class).as(StepVerifier::create).consumeNextWith(actual -> assertThat(actual.hasTransaction()).isFalse()).verifyComplete();
tm.getReactiveTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED)).cast(GenericReactiveTransaction.class).contextWrite(TransactionContextManager.createTransactionContext()).as(StepVerifier::create).consumeNextWith(actual -> {
assertThat(actual.hasTransaction()).isTrue();
assertThat(actual.isNewTransaction()).isTrue();
}).verifyComplete();
tm.getReactiveTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_MANDATORY)).contextWrite(TransactionContextManager.createTransactionContext()).cast(GenericReactiveTransaction.class).as(StepVerifier::create).expectError(IllegalTransactionStateException.class).verify();
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class AbstractReactiveTransactionManager method getReactiveTransaction.
// ---------------------------------------------------------------------
// Implementation of ReactiveTransactionManager
// ---------------------------------------------------------------------
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
return TransactionSynchronizationManager.forCurrentTransaction().flatMap(synchronizationManager -> {
Object transaction = doGetTransaction(synchronizationManager);
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(synchronizationManager, def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
return Mono.error(new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()));
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
return Mono.error(new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'"));
} else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
return TransactionContextManager.currentContext().map(TransactionSynchronizationManager::new).flatMap(nestedSynchronizationManager -> suspend(nestedSynchronizationManager, null).map(Optional::of).defaultIfEmpty(Optional.empty()).flatMap(suspendedResources -> {
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
return Mono.defer(() -> {
GenericReactiveTransaction status = newReactiveTransaction(nestedSynchronizationManager, def, transaction, true, debugEnabled, suspendedResources.orElse(null));
return doBegin(nestedSynchronizationManager, transaction, def).doOnSuccess(ignore -> prepareSynchronization(nestedSynchronizationManager, status, def)).thenReturn(status);
}).onErrorResume(ErrorPredicates.RUNTIME_OR_ERROR, ex -> resume(nestedSynchronizationManager, null, suspendedResources.orElse(null)).then(Mono.error(ex)));
}));
} else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + def);
}
return Mono.just(prepareReactiveTransaction(synchronizationManager, def, null, true, debugEnabled, null));
}
});
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class AbstractReactiveTransactionAspectTests method cannotCreateTransaction.
/**
* Simulate a transaction infrastructure failure.
* Shouldn't invoke target method.
*/
@Test
public void cannotCreateTransaction() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
Method m = getNameMethod;
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(m, txatt);
ReactiveTransactionManager rtm = mock(ReactiveTransactionManager.class);
// Expect a transaction
CannotCreateTransactionException ex = new CannotCreateTransactionException("foobar", null);
given(rtm.getReactiveTransaction(txatt)).willThrow(ex);
DefaultTestBean tb = new DefaultTestBean() {
@Override
public Mono<String> getName() {
throw new UnsupportedOperationException("Shouldn't have invoked target method when couldn't create transaction for transactional method");
}
};
TestBean itb = (TestBean) advised(tb, rtm, tas);
itb.getName().as(StepVerifier::create).expectError(CannotCreateTransactionException.class).verify();
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class AbstractReactiveTransactionAspectTests method cannotCommitTransaction.
/**
* Simulate failure of the underlying transaction infrastructure to commit.
* Check that the target method was invoked, but that the transaction
* infrastructure exception was thrown to the client
*/
@Test
public void cannotCommitTransaction() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
Method m = setNameMethod;
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(m, txatt);
// Method m2 = getNameMethod;
// No attributes for m2
ReactiveTransactionManager rtm = mock(ReactiveTransactionManager.class);
ReactiveTransaction status = mock(ReactiveTransaction.class);
given(rtm.getReactiveTransaction(txatt)).willReturn(Mono.just(status));
UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null);
given(rtm.commit(status)).willReturn(Mono.error(ex));
given(rtm.rollback(status)).willReturn(Mono.empty());
DefaultTestBean tb = new DefaultTestBean();
TestBean itb = (TestBean) advised(tb, rtm, tas);
String name = "new name";
Mono.from(itb.setName(name)).as(StepVerifier::create).consumeErrorWith(throwable -> {
assertThat(throwable.getClass()).isEqualTo(RuntimeException.class);
assertThat(throwable.getCause()).isEqualTo(ex);
}).verify();
// Should have invoked target and changed name
itb.getName().as(StepVerifier::create).expectNext(name).verifyComplete();
}
Aggregations