diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java index 5a279df74da..46dc6b0a919 100644 --- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java +++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java @@ -29,7 +29,6 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.lang.Nullable; import org.springframework.transaction.CannotCreateTransactionException; import org.springframework.transaction.TransactionDefinition; -import org.springframework.transaction.TransactionException; import org.springframework.transaction.reactive.AbstractReactiveTransactionManager; import org.springframework.transaction.reactive.GenericReactiveTransaction; import org.springframework.transaction.reactive.TransactionSynchronizationManager; @@ -162,7 +161,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager } @Override - protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) throws TransactionException { + protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) { ConnectionFactoryTransactionObject txObject = new ConnectionFactoryTransactionObject(); ConnectionHolder conHolder = (ConnectionHolder) synchronizationManager.getResource(obtainConnectionFactory()); txObject.setConnectionHolder(conHolder, false); @@ -178,7 +177,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager @SuppressWarnings("deprecation") @Override protected Mono doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction, - TransactionDefinition definition) throws TransactionException { + TransactionDefinition definition) { ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction; @@ -243,9 +242,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager } @Override - protected Mono doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction) - throws TransactionException { - + protected Mono doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction) { return Mono.defer(() -> { ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction; txObject.setConnectionHolder(null); @@ -255,7 +252,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager @Override protected Mono doResume(TransactionSynchronizationManager synchronizationManager, - @Nullable Object transaction, Object suspendedResources) throws TransactionException { + @Nullable Object transaction, Object suspendedResources) { return Mono.defer(() -> { synchronizationManager.bindResource(obtainConnectionFactory(), suspendedResources); @@ -265,7 +262,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager @Override protected Mono doCommit(TransactionSynchronizationManager TransactionSynchronizationManager, - GenericReactiveTransaction status) throws TransactionException { + GenericReactiveTransaction status) { ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction(); Connection connection = txObject.getConnectionHolder().getConnection(); @@ -278,7 +275,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager @Override protected Mono doRollback(TransactionSynchronizationManager TransactionSynchronizationManager, - GenericReactiveTransaction status) throws TransactionException { + GenericReactiveTransaction status) { ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction(); Connection connection = txObject.getConnectionHolder().getConnection(); @@ -291,7 +288,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager @Override protected Mono doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager, - GenericReactiveTransaction status) throws TransactionException { + GenericReactiveTransaction status) { return Mono.fromRunnable(() -> { ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction(); diff --git a/spring-tx/src/main/java/org/springframework/transaction/ReactiveTransactionManager.java b/spring-tx/src/main/java/org/springframework/transaction/ReactiveTransactionManager.java index 64341ebb031..d55a13472dd 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/ReactiveTransactionManager.java +++ b/spring-tx/src/main/java/org/springframework/transaction/ReactiveTransactionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,8 @@ public interface ReactiveTransactionManager extends TransactionManager { *

An exception to the above rule is the read-only flag, which should be * ignored if no explicit read-only mode is supported. Essentially, the * read-only flag is just a hint for potential optimization. + *

Note: In contrast to {@link PlatformTransactionManager}, exceptions + * are propagated through the reactive pipeline returned from this method. * @param definition the TransactionDefinition instance, * describing propagation behavior, isolation level, timeout etc. * @return transaction status object representing the new or current transaction @@ -58,8 +60,7 @@ public interface ReactiveTransactionManager extends TransactionManager { * @see TransactionDefinition#getTimeout * @see TransactionDefinition#isReadOnly */ - Mono getReactiveTransaction(@Nullable TransactionDefinition definition) - throws TransactionException; + Mono getReactiveTransaction(@Nullable TransactionDefinition definition); /** * Commit the given transaction, with regard to its status. If the transaction @@ -69,14 +70,12 @@ public interface ReactiveTransactionManager extends TransactionManager { * has been suspended to be able to create a new one, resume the previous * transaction after committing the new one. *

Note that when the commit call completes, no matter if normally or - * throwing an exception, the transaction must be fully completed and + * propagating an exception, the transaction must be fully completed and * cleaned up. No rollback call should be expected in such a case. - *

If this method throws an exception other than a TransactionException, - * then some before-commit error caused the commit attempt to fail. For - * example, an O/R Mapping tool might have tried to flush changes to the - * database right before commit, with the resulting DataAccessException - * causing the transaction to fail. The original exception will be - * propagated to the caller of this commit method in such a case. + *

Note: In contrast to {@link PlatformTransactionManager}, exceptions + * are propagated through the reactive pipeline returned from this method. + * Also, depending on the transaction manager implementation, {@code commit} + * may propagate {@link org.springframework.dao.DataAccessException} as well. * @param transaction object returned by the {@code getTransaction} method * @throws UnexpectedRollbackException in case of an unexpected rollback * that the transaction coordinator initiated @@ -88,7 +87,7 @@ public interface ReactiveTransactionManager extends TransactionManager { * is already completed (that is, committed or rolled back) * @see ReactiveTransaction#setRollbackOnly */ - Mono commit(ReactiveTransaction transaction) throws TransactionException; + Mono commit(ReactiveTransaction transaction); /** * Perform a rollback of the given transaction. @@ -96,16 +95,20 @@ public interface ReactiveTransactionManager extends TransactionManager { * participation in the surrounding transaction. If a previous transaction * has been suspended to be able to create a new one, resume the previous * transaction after rolling back the new one. - *

Do not call rollback on a transaction if commit threw an exception. + *

Do not call rollback on a transaction if commit failed. * The transaction will already have been completed and cleaned up when commit * returns, even in case of a commit exception. Consequently, a rollback call * after commit failure will lead to an IllegalTransactionStateException. + *

Note: In contrast to {@link PlatformTransactionManager}, exceptions + * are propagated through the reactive pipeline returned from this method. + * Also, depending on the transaction manager implementation, {@code rollback} + * may propagate {@link org.springframework.dao.DataAccessException} as well. * @param transaction object returned by the {@code getTransaction} method * @throws TransactionSystemException in case of rollback or system errors * (typically caused by fundamental resource failures) * @throws IllegalTransactionStateException if the given transaction * is already completed (that is, committed or rolled back) */ - Mono rollback(ReactiveTransaction transaction) throws TransactionException; + Mono rollback(ReactiveTransaction transaction); } diff --git a/spring-tx/src/main/java/org/springframework/transaction/reactive/AbstractReactiveTransactionManager.java b/spring-tx/src/main/java/org/springframework/transaction/reactive/AbstractReactiveTransactionManager.java index cdc434fc736..ba85becf0dc 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/reactive/AbstractReactiveTransactionManager.java +++ b/spring-tx/src/main/java/org/springframework/transaction/reactive/AbstractReactiveTransactionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -95,9 +95,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @see #doBegin */ @Override - public final Mono getReactiveTransaction(@Nullable TransactionDefinition definition) - throws TransactionException { - + public final Mono getReactiveTransaction(@Nullable TransactionDefinition definition) { // Use defaults if no transaction definition given. TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults()); @@ -165,7 +163,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * Create a ReactiveTransaction for an existing transaction. */ private Mono handleExistingTransaction(TransactionSynchronizationManager synchronizationManager, - TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { + TransactionDefinition definition, Object transaction, boolean debugEnabled) { if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) { return Mono.error(new IllegalTransactionStateException( @@ -277,7 +275,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @see #resume */ private Mono suspend(TransactionSynchronizationManager synchronizationManager, - @Nullable Object transaction) throws TransactionException { + @Nullable Object transaction) { if (synchronizationManager.isSynchronizationActive()) { Mono> suspendedSynchronizations = doSuspendSynchronization(synchronizationManager); @@ -325,8 +323,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @see #suspend */ private Mono resume(TransactionSynchronizationManager synchronizationManager, - @Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) - throws TransactionException { + @Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) { Mono resume = Mono.empty(); @@ -403,7 +400,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @see #rollback */ @Override - public final Mono commit(ReactiveTransaction transaction) throws TransactionException { + public final Mono commit(ReactiveTransaction transaction) { if (transaction.isCompleted()) { return Mono.error(new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction")); @@ -426,10 +423,9 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * Rollback-only flags have already been checked and applied. * @param synchronizationManager the synchronization manager bound to the current transaction * @param status object representing the transaction - * @throws TransactionException in case of commit failure */ private Mono processCommit(TransactionSynchronizationManager synchronizationManager, - GenericReactiveTransaction status) throws TransactionException { + GenericReactiveTransaction status) { AtomicBoolean beforeCompletionInvoked = new AtomicBoolean(); @@ -487,7 +483,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @see #doSetRollbackOnly */ @Override - public final Mono rollback(ReactiveTransaction transaction) throws TransactionException { + public final Mono rollback(ReactiveTransaction transaction) { if (transaction.isCompleted()) { return Mono.error(new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction")); @@ -503,7 +499,6 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * The completed flag has already been checked. * @param synchronizationManager the synchronization manager bound to the current transaction * @param status object representing the transaction - * @throws TransactionException in case of rollback failure */ private Mono processRollback(TransactionSynchronizationManager synchronizationManager, GenericReactiveTransaction status) { @@ -542,11 +537,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @param synchronizationManager the synchronization manager bound to the current transaction * @param status object representing the transaction * @param ex the thrown application exception or error - * @throws TransactionException in case of rollback failure * @see #doRollback */ private Mono doRollbackOnCommitException(TransactionSynchronizationManager synchronizationManager, - GenericReactiveTransaction status, Throwable ex) throws TransactionException { + GenericReactiveTransaction status, Throwable ex) { return Mono.defer(() -> { if (status.isNewTransaction()) { @@ -714,14 +708,12 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @return the current transaction object * @throws org.springframework.transaction.CannotCreateTransactionException * if transaction support is not available - * @throws TransactionException in case of lookup or system errors * @see #doBegin * @see #doCommit * @see #doRollback * @see GenericReactiveTransaction#getTransaction */ - protected abstract Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) - throws TransactionException; + protected abstract Object doGetTransaction(TransactionSynchronizationManager synchronizationManager); /** * Check if the given transaction object indicates an existing transaction @@ -735,10 +727,9 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * Subclasses are of course encouraged to provide such support. * @param transaction the transaction object returned by doGetTransaction * @return if there is an existing transaction - * @throws TransactionException in case of system errors * @see #doGetTransaction */ - protected boolean isExistingTransaction(Object transaction) throws TransactionException { + protected boolean isExistingTransaction(Object transaction) { return false; } @@ -757,12 +748,11 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @param transaction the transaction object returned by {@code doGetTransaction} * @param definition a TransactionDefinition instance, describing propagation * behavior, isolation level, read-only flag, timeout, and transaction name - * @throws TransactionException in case of creation or system errors * @throws org.springframework.transaction.NestedTransactionNotSupportedException * if the underlying transaction does not support nesting (e.g. through savepoints) */ protected abstract Mono doBegin(TransactionSynchronizationManager synchronizationManager, - Object transaction, TransactionDefinition definition) throws TransactionException; + Object transaction, TransactionDefinition definition); /** * Suspend the resources of the current transaction. @@ -775,11 +765,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * (will be kept unexamined for passing it into doResume) * @throws org.springframework.transaction.TransactionSuspensionNotSupportedException * if suspending is not supported by the transaction manager implementation - * @throws TransactionException in case of system errors * @see #doResume */ protected Mono doSuspend(TransactionSynchronizationManager synchronizationManager, - Object transaction) throws TransactionException { + Object transaction) { throw new TransactionSuspensionNotSupportedException( "Transaction manager [" + getClass().getName() + "] does not support transaction suspension"); @@ -796,11 +785,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * as returned by doSuspend * @throws org.springframework.transaction.TransactionSuspensionNotSupportedException * if suspending is not supported by the transaction manager implementation - * @throws TransactionException in case of system errors * @see #doSuspend */ protected Mono doResume(TransactionSynchronizationManager synchronizationManager, - @Nullable Object transaction, Object suspendedResources) throws TransactionException { + @Nullable Object transaction, Object suspendedResources) { throw new TransactionSuspensionNotSupportedException( "Transaction manager [" + getClass().getName() + "] does not support transaction suspension"); @@ -830,11 +818,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * contained in the passed-in status. * @param synchronizationManager the synchronization manager bound to the current transaction * @param status the status representation of the transaction - * @throws TransactionException in case of commit or system errors * @see GenericReactiveTransaction#getTransaction */ protected abstract Mono doCommit(TransactionSynchronizationManager synchronizationManager, - GenericReactiveTransaction status) throws TransactionException; + GenericReactiveTransaction status); /** * Perform an actual rollback of the given transaction. @@ -843,11 +830,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * will be performed on the transaction object contained in the passed-in status. * @param synchronizationManager the synchronization manager bound to the current transaction * @param status the status representation of the transaction - * @throws TransactionException in case of system errors * @see GenericReactiveTransaction#getTransaction */ protected abstract Mono doRollback(TransactionSynchronizationManager synchronizationManager, - GenericReactiveTransaction status) throws TransactionException; + GenericReactiveTransaction status); /** * Set the given transaction rollback-only. Only called on rollback @@ -857,10 +843,9 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * supported. Subclasses are of course encouraged to provide such support. * @param synchronizationManager the synchronization manager bound to the current transaction * @param status the status representation of the transaction - * @throws TransactionException in case of system errors */ protected Mono doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager, - GenericReactiveTransaction status) throws TransactionException { + GenericReactiveTransaction status) { throw new IllegalTransactionStateException( "Participating in existing transactions is not supported - when 'isExistingTransaction' " + @@ -878,13 +863,12 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran * @param synchronizationManager the synchronization manager bound to the current transaction * @param transaction the transaction object returned by {@code doGetTransaction} * @param synchronizations a List of TransactionSynchronization objects - * @throws TransactionException in case of system errors * @see #invokeAfterCompletion(TransactionSynchronizationManager, List, int) * @see TransactionSynchronization#afterCompletion(int) * @see TransactionSynchronization#STATUS_UNKNOWN */ protected Mono registerAfterCompletionWithExistingTransaction(TransactionSynchronizationManager synchronizationManager, - Object transaction, List synchronizations) throws TransactionException { + Object transaction, List synchronizations) { logger.debug("Cannot register Spring after-completion synchronization with existing transaction - " + "processing Spring after-completion callbacks immediately, with outcome status 'unknown'");