Skip to content

Commit

Permalink
Clarify ReactiveTransactionManager exception declarations
Browse files Browse the repository at this point in the history
Avoid misleading "throws TransactionException" declarations but preserve javadoc "@throws" notes for specific exceptions (with reactive propagation semantics).

Closes gh-30817
  • Loading branch information
jhoeller committed Jul 5, 2023
1 parent c5771bc commit 79df1da
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 56 deletions.
Expand Up @@ -30,7 +30,6 @@
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;
Expand Down Expand Up @@ -170,7 +169,7 @@ public void afterPropertiesSet() {
}

@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);
Expand All @@ -184,7 +183,7 @@ protected boolean isExistingTransaction(Object transaction) {

@Override
protected Mono<Void> doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction,
TransactionDefinition definition) throws TransactionException {
TransactionDefinition definition) {

ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;

Expand Down Expand Up @@ -275,9 +274,7 @@ protected Duration determineTimeout(TransactionDefinition definition) {
}

@Override
protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction)
throws TransactionException {

protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction) {
return Mono.defer(() -> {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
txObject.setConnectionHolder(null);
Expand All @@ -287,7 +284,7 @@ protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizati

@Override
protected Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager,
@Nullable Object transaction, Object suspendedResources) throws TransactionException {
@Nullable Object transaction, Object suspendedResources) {

return Mono.defer(() -> {
synchronizationManager.bindResource(obtainConnectionFactory(), suspendedResources);
Expand All @@ -297,7 +294,7 @@ protected Mono<Void> doResume(TransactionSynchronizationManager synchronizationM

@Override
protected Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynchronizationManager,
GenericReactiveTransaction status) throws TransactionException {
GenericReactiveTransaction status) {

ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
if (status.isDebug()) {
Expand All @@ -309,7 +306,7 @@ protected Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynch

@Override
protected Mono<Void> doRollback(TransactionSynchronizationManager TransactionSynchronizationManager,
GenericReactiveTransaction status) throws TransactionException {
GenericReactiveTransaction status) {

ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
if (status.isDebug()) {
Expand All @@ -321,7 +318,7 @@ protected Mono<Void> doRollback(TransactionSynchronizationManager TransactionSyn

@Override
protected Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) throws TransactionException {
GenericReactiveTransaction status) {

return Mono.fromRunnable(() -> {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
Expand Down
@@ -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.
Expand Down Expand Up @@ -46,6 +46,8 @@ public interface ReactiveTransactionManager extends TransactionManager {
* <p>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.
* <p>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
Expand All @@ -58,8 +60,7 @@ public interface ReactiveTransactionManager extends TransactionManager {
* @see TransactionDefinition#getTimeout
* @see TransactionDefinition#isReadOnly
*/
Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition);

/**
* Commit the given transaction, with regard to its status. If the transaction
Expand All @@ -69,14 +70,12 @@ Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition
* has been suspended to be able to create a new one, resume the previous
* transaction after committing the new one.
* <p>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.
* <p>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.
* <p>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
Expand All @@ -88,24 +87,28 @@ Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition
* is already completed (that is, committed or rolled back)
* @see ReactiveTransaction#setRollbackOnly
*/
Mono<Void> commit(ReactiveTransaction transaction) throws TransactionException;
Mono<Void> commit(ReactiveTransaction transaction);

/**
* Perform a rollback of the given transaction.
* <p>If the transaction wasn't a new one, just set it rollback-only for proper
* 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.
* <p><b>Do not call rollback on a transaction if commit threw an exception.</b>
* <p><b>Do not call rollback on a transaction if commit failed.</b>
* 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.
* <p>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<Void> rollback(ReactiveTransaction transaction) throws TransactionException;
Mono<Void> rollback(ReactiveTransaction transaction);

}

0 comments on commit 79df1da

Please sign in to comment.