use of org.springframework.transaction.ReactiveTransactionManager in project spring-boot by spring-projects.
the class TransactionAutoConfigurationTests method whenThereAreBothReactiveAndPlatformTransactionManagersATemplateAndAnOperatorAreAutoConfigured.
@Test
void whenThereAreBothReactiveAndPlatformTransactionManagersATemplateAndAnOperatorAreAutoConfigured() {
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class)).withUserConfiguration(SinglePlatformTransactionManagerConfiguration.class, SingleReactiveTransactionManagerConfiguration.class).withPropertyValues("spring.datasource.url:jdbc:h2:mem:" + UUID.randomUUID()).run((context) -> {
PlatformTransactionManager platformTransactionManager = context.getBean(PlatformTransactionManager.class);
TransactionTemplate transactionTemplate = context.getBean(TransactionTemplate.class);
assertThat(transactionTemplate.getTransactionManager()).isSameAs(platformTransactionManager);
ReactiveTransactionManager reactiveTransactionManager = context.getBean(ReactiveTransactionManager.class);
TransactionalOperator transactionalOperator = context.getBean(TransactionalOperator.class);
assertThat(transactionalOperator).extracting("transactionManager").isSameAs(reactiveTransactionManager);
});
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-boot by spring-projects.
the class TransactionAutoConfigurationTests method whenThereIsASingleReactiveTransactionManagerATransactionalOperatorIsAutoConfigured.
@Test
void whenThereIsASingleReactiveTransactionManagerATransactionalOperatorIsAutoConfigured() {
this.contextRunner.withUserConfiguration(SingleReactiveTransactionManagerConfiguration.class).run((context) -> {
ReactiveTransactionManager transactionManager = context.getBean(ReactiveTransactionManager.class);
TransactionalOperator transactionalOperator = context.getBean(TransactionalOperator.class);
assertThat(transactionalOperator).extracting("transactionManager").isSameAs(transactionManager);
});
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class TransactionAspectSupport method invokeWithinTransaction.
/**
* General delegate for around-advice-based subclasses, delegating to several other template
* methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
* as well as regular {@link PlatformTransactionManager} implementations and
* {@link ReactiveTransactionManager} implementations for reactive return types.
* @param method the Method being invoked
* @param targetClass the target class that we're invoking the method on
* @param invocation the callback to use for proceeding with the target invocation
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
boolean hasSuspendingFlowReturnType = isSuspendingFunction && COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
throw new IllegalStateException("Coroutines invocation not supported: " + method);
}
CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
Class<?> reactiveType = (isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " + method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
InvocationCallback callback = invocation;
if (corInv != null) {
callback = () -> CoroutinesUtils.invokeSuspendingFunction(method, corInv.getTarget(), corInv.getArguments());
}
Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, (ReactiveTransactionManager) tm);
if (corInv != null) {
Publisher<?> pr = (Publisher<?>) result;
return (hasSuspendingFlowReturnType ? KotlinDelegate.asFlow(pr) : KotlinDelegate.awaitSingleOrNull(pr, corInv.getContinuation()));
}
return result;
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
commitTransactionAfterReturning(txInfo);
return retVal;
} else {
Object result;
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
} catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
} else {
throw new ThrowableHolderException(ex);
}
} else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
} finally {
cleanupTransactionInfo(txInfo);
}
});
} catch (ThrowableHolderException ex) {
throw ex.getCause();
} catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
} catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class AbstractReactiveTransactionAspectTests method noTransaction.
@Test
public void noTransaction() throws Exception {
ReactiveTransactionManager rtm = mock(ReactiveTransactionManager.class);
DefaultTestBean tb = new DefaultTestBean();
TransactionAttributeSource tas = new MapTransactionAttributeSource();
// All the methods in this class use the advised() template method
// to obtain a transaction object, configured with the when PlatformTransactionManager
// and transaction attribute source
TestBean itb = (TestBean) advised(tb, rtm, tas);
checkReactiveTransaction(false);
itb.getName();
checkReactiveTransaction(false);
// expect no calls
verifyNoInteractions(rtm);
}
use of org.springframework.transaction.ReactiveTransactionManager in project spring-framework by spring-projects.
the class AbstractReactiveTransactionAspectTests method transactionShouldSucceedWithNotNew.
/**
* Check that a transaction is created and committed.
*/
@Test
public void transactionShouldSucceedWithNotNew() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(getNameMethod, 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, tas);
itb.getName().as(StepVerifier::create).verifyComplete();
verify(rtm).commit(status);
}
Aggregations