Search in sources :

Example 1 with ReactiveTransactionManager

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);
    });
}
Also used : TransactionalOperator(org.springframework.transaction.reactive.TransactionalOperator) TransactionTemplate(org.springframework.transaction.support.TransactionTemplate) ReactiveTransactionManager(org.springframework.transaction.ReactiveTransactionManager) PlatformTransactionManager(org.springframework.transaction.PlatformTransactionManager) Test(org.junit.jupiter.api.Test)

Example 2 with 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);
    });
}
Also used : TransactionalOperator(org.springframework.transaction.reactive.TransactionalOperator) ReactiveTransactionManager(org.springframework.transaction.ReactiveTransactionManager) Test(org.junit.jupiter.api.Test)

Example 3 with ReactiveTransactionManager

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;
    }
}
Also used : Continuation(kotlin.coroutines.Continuation) AwaitKt(kotlinx.coroutines.reactive.AwaitKt) ReactiveTransaction(org.springframework.transaction.ReactiveTransaction) InitializingBean(org.springframework.beans.factory.InitializingBean) ConcurrentMap(java.util.concurrent.ConcurrentMap) ConcurrentReferenceHashMap(org.springframework.util.ConcurrentReferenceHashMap) KotlinDetector(org.springframework.core.KotlinDetector) TransactionManager(org.springframework.transaction.TransactionManager) TransactionSystemException(org.springframework.transaction.TransactionSystemException) BeanFactoryAware(org.springframework.beans.factory.BeanFactoryAware) MethodParameter(org.springframework.core.MethodParameter) Nullable(org.springframework.lang.Nullable) Method(java.lang.reflect.Method) BeanFactoryAnnotationUtils(org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils) ReactiveAdapterRegistry(org.springframework.core.ReactiveAdapterRegistry) ReactiveFlowKt(kotlinx.coroutines.reactive.ReactiveFlowKt) CoroutinesUtils(org.springframework.core.CoroutinesUtils) TransactionContextManager(org.springframework.transaction.reactive.TransactionContextManager) ReactiveAdapter(org.springframework.core.ReactiveAdapter) Properties(java.util.Properties) ClassUtils(org.springframework.util.ClassUtils) CallbackPreferringPlatformTransactionManager(org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager) Publisher(org.reactivestreams.Publisher) Mono(reactor.core.publisher.Mono) ReactiveTransactionManager(org.springframework.transaction.ReactiveTransactionManager) NamedThreadLocal(org.springframework.core.NamedThreadLocal) Flux(reactor.core.publisher.Flux) Try(io.vavr.control.Try) NoTransactionException(org.springframework.transaction.NoTransactionException) PlatformTransactionManager(org.springframework.transaction.PlatformTransactionManager) BeanFactory(org.springframework.beans.factory.BeanFactory) TransactionStatus(org.springframework.transaction.TransactionStatus) Log(org.apache.commons.logging.Log) LogFactory(org.apache.commons.logging.LogFactory) Assert(org.springframework.util.Assert) StringUtils(org.springframework.util.StringUtils) TransactionStatus(org.springframework.transaction.TransactionStatus) TransactionSystemException(org.springframework.transaction.TransactionSystemException) CallbackPreferringPlatformTransactionManager(org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager) ReactiveAdapter(org.springframework.core.ReactiveAdapter) Mono(reactor.core.publisher.Mono) Flux(reactor.core.publisher.Flux) Publisher(org.reactivestreams.Publisher) CallbackPreferringPlatformTransactionManager(org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager) PlatformTransactionManager(org.springframework.transaction.PlatformTransactionManager) TransactionManager(org.springframework.transaction.TransactionManager) CallbackPreferringPlatformTransactionManager(org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager) ReactiveTransactionManager(org.springframework.transaction.ReactiveTransactionManager) PlatformTransactionManager(org.springframework.transaction.PlatformTransactionManager) ReactiveTransactionManager(org.springframework.transaction.ReactiveTransactionManager) MethodParameter(org.springframework.core.MethodParameter) Nullable(org.springframework.lang.Nullable)

Example 4 with ReactiveTransactionManager

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);
}
Also used : ReactiveTransactionManager(org.springframework.transaction.ReactiveTransactionManager) Test(org.junit.jupiter.api.Test)

Example 5 with ReactiveTransactionManager

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);
}
Also used : ReactiveTransaction(org.springframework.transaction.ReactiveTransaction) ReactiveTransactionManager(org.springframework.transaction.ReactiveTransactionManager) Test(org.junit.jupiter.api.Test)

Aggregations

ReactiveTransactionManager (org.springframework.transaction.ReactiveTransactionManager)13 Test (org.junit.jupiter.api.Test)11 ReactiveTransaction (org.springframework.transaction.ReactiveTransaction)9 Mono (reactor.core.publisher.Mono)6 Method (java.lang.reflect.Method)4 Assertions.assertThat (org.assertj.core.api.Assertions.assertThat)4 Flux (reactor.core.publisher.Flux)4 StepVerifier (reactor.test.StepVerifier)4 Publisher (org.reactivestreams.Publisher)3 CannotCreateTransactionException (org.springframework.transaction.CannotCreateTransactionException)3 IllegalTransactionStateException (org.springframework.transaction.IllegalTransactionStateException)3 TransactionDefinition (org.springframework.transaction.TransactionDefinition)3 TransactionSystemException (org.springframework.transaction.TransactionSystemException)3 UnexpectedRollbackException (org.springframework.transaction.UnexpectedRollbackException)3 Log (org.apache.commons.logging.Log)2 LogFactory (org.apache.commons.logging.LogFactory)2 Fail.fail (org.assertj.core.api.Fail.fail)2 BeforeEach (org.junit.jupiter.api.BeforeEach)2 BDDMockito.given (org.mockito.BDDMockito.given)2 Mockito.mock (org.mockito.Mockito.mock)2