org.springframework.r2dbc.connection

## Class R2dbcTransactionManager

- java.lang.Object
- - org.springframework.transaction.reactive.AbstractReactiveTransactionManager
  - - org.springframework.r2dbc.connection.R2dbcTransactionManager

- All Implemented Interfaces:
    Serializable, InitializingBean, ReactiveTransactionManager, TransactionManager

      public class R2dbcTransactionManager
      extends AbstractReactiveTransactionManager
      implements InitializingBean

  `ReactiveTransactionManager` implementation for a single R2DBC `ConnectionFactory`. This class is capable of working in any environment with any R2DBC driver, as long as the setup uses a `ConnectionFactory` as its `Connection` factory mechanism. Binds a R2DBC `Connection` from the specified `ConnectionFactory` to the current subscriber context, potentially allowing for one context-bound `Connection` per `ConnectionFactory`.

  Note: The `ConnectionFactory` that this transaction manager operates on needs to return independent `Connection`s. The `Connection`s typically come from a connection pool but the `ConnectionFactory` must not return specifically scoped or constrained `Connection`s. This transaction manager will associate `Connection` with context-bound transactions, according to the specified propagation behavior. It assumes that a separate, independent `Connection` can be obtained even during an ongoing transaction.

  Application code is required to retrieve the R2DBC Connection via `ConnectionFactoryUtils.getConnection(ConnectionFactory)` instead of a standard R2DBC-style `ConnectionFactory.create()` call. Spring classes such as `DatabaseClient` use this strategy implicitly. If not used in combination with this transaction manager, the `ConnectionFactoryUtils` lookup strategy behaves exactly like the native `ConnectionFactory` lookup; it can thus be used in a portable fashion.

  Alternatively, you can allow application code to work with the lookup pattern `ConnectionFactory.create()`, for example for code not aware of Spring. In that case, define a `TransactionAwareConnectionFactoryProxy` for your target `ConnectionFactory`, and pass that proxy `ConnectionFactory` to your DAOs which will automatically participate in Spring-managed transactions when accessing it.

  Since:
    5.3
  Author:
    Mark Paluch
  See Also:
    `ConnectionFactoryUtils.getConnection(ConnectionFactory)`, `ConnectionFactoryUtils.releaseConnection(io.r2dbc.spi.Connection, io.r2dbc.spi.ConnectionFactory)`, `TransactionAwareConnectionFactoryProxy`, Serialized Form

- - ### Nested Class Summary

    - ### Nested classes/interfaces inherited from class org.springframework.transaction.reactive.AbstractReactiveTransactionManager

      `AbstractReactiveTransactionManager.SuspendedResourcesHolder`

  - ### Field Summary

    - ### Fields inherited from class org.springframework.transaction.reactive.AbstractReactiveTransactionManager

      `logger`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `R2dbcTransactionManager()` Create a new `R2dbcTransactionManager` instance.
    `R2dbcTransactionManager(io.r2dbc.spi.ConnectionFactory connectionFactory)` Create a new `R2dbcTransactionManager` instance.

  - ### Method Summary

    All Methods Instance Methods Concrete Methods Deprecated Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `afterPropertiesSet()` Invoked by the containing `BeanFactory` after it has set all bean properties and satisfied `BeanFactoryAware`, `ApplicationContextAware` etc.
    `protected Duration` | `determineTimeout(TransactionDefinition definition)` Determine the actual timeout to use for the given definition.
    `protected reactor.core.publisher.Mono<Void>` | `doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction, TransactionDefinition definition)` Begin a new transaction with semantics according to the given transaction definition.
    `protected reactor.core.publisher.Mono<Void>` | `doCleanupAfterCompletion(TransactionSynchronizationManager synchronizationManager, Object transaction)` Cleanup resources after transaction completion.
    `protected reactor.core.publisher.Mono<Void>` | `doCommit(TransactionSynchronizationManager TransactionSynchronizationManager, GenericReactiveTransaction status)` Perform an actual commit of the given transaction.
    `protected Object` | `doGetTransaction(TransactionSynchronizationManager synchronizationManager)` Return a transaction object for the current transaction state.
    `protected reactor.core.publisher.Mono<Void>` | `doResume(TransactionSynchronizationManager synchronizationManager, Object transaction, Object suspendedResources)` Resume the resources of the current transaction.
    `protected reactor.core.publisher.Mono<Void>` | `doRollback(TransactionSynchronizationManager TransactionSynchronizationManager, GenericReactiveTransaction status)` Perform an actual rollback of the given transaction.
    `protected reactor.core.publisher.Mono<Void>` | `doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager, GenericReactiveTransaction status)` Set the given transaction rollback-only.
    `protected reactor.core.publisher.Mono<Object>` | `doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction)` Suspend the resources of the current transaction.
    `io.r2dbc.spi.ConnectionFactory` | `getConnectionFactory()` Return the R2DBC `ConnectionFactory` that this instance manages transactions for.
    `boolean` | `isEnforceReadOnly()` Return whether to enforce the read-only nature of a transaction through an explicit statement on the transactional connection.
    `protected boolean` | `isExistingTransaction(Object transaction)` Check if the given transaction object indicates an existing transaction (that is, a transaction which has already started).
    `protected io.r2dbc.spi.ConnectionFactory` | `obtainConnectionFactory()` Obtain the `ConnectionFactory` for actual use.
    `protected reactor.core.publisher.Mono<Void>` | `prepareTransactionalConnection(io.r2dbc.spi.Connection con, TransactionDefinition definition)` Prepare the transactional `Connection` right after transaction begin.
    `protected reactor.core.publisher.Mono<Void>` | `prepareTransactionalConnection(io.r2dbc.spi.Connection con, TransactionDefinition definition, Object transaction)` Deprecated. in favor of `prepareTransactionalConnection(Connection, TransactionDefinition)` since this variant gets called too early (before transaction begin) for read-only customization
    `protected io.r2dbc.spi.IsolationLevel` | `resolveIsolationLevel(int isolationLevel)` Resolve the isolation level constant to a R2DBC `IsolationLevel`.
    `void` | `setConnectionFactory(io.r2dbc.spi.ConnectionFactory connectionFactory)` Set the R2DBC `ConnectionFactory` that this instance should manage transactions for.
    `void` | `setEnforceReadOnly(boolean enforceReadOnly)` Specify whether to enforce the read-only nature of a transaction (as indicated by `TransactionDefinition.isReadOnly()`) through an explicit statement on the transactional connection: "SET TRANSACTION READ ONLY" as understood by Oracle, MySQL and Postgres.
    `protected RuntimeException` | `translateException(String task, io.r2dbc.spi.R2dbcException ex)` Translate the given R2DBC commit/rollback exception to a common Spring exception to propagate from the `AbstractReactiveTransactionManager.commit(org.springframework.transaction.ReactiveTransaction)`/`AbstractReactiveTransactionManager.rollback(org.springframework.transaction.ReactiveTransaction)` call.

    - ### Methods inherited from class org.springframework.transaction.reactive.AbstractReactiveTransactionManager

      `commit, getReactiveTransaction, prepareForCommit, registerAfterCompletionWithExistingTransaction, rollback`

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### R2dbcTransactionManager

          public R2dbcTransactionManager()

      Create a new `R2dbcTransactionManager` instance. A `ConnectionFactory` has to be set to be able to use it.
      See Also:
        `setConnectionFactory(io.r2dbc.spi.ConnectionFactory)`

    - #### R2dbcTransactionManager

          public R2dbcTransactionManager(io.r2dbc.spi.ConnectionFactory connectionFactory)

      Create a new `R2dbcTransactionManager` instance.
      Parameters:
        `connectionFactory` - the R2DBC ConnectionFactory to manage transactions for

  - ### Method Detail

    - #### setConnectionFactory

          public void setConnectionFactory(@Nullable
                                           io.r2dbc.spi.ConnectionFactory connectionFactory)

      Set the R2DBC `ConnectionFactory` that this instance should manage transactions for. This will typically be a locally defined `ConnectionFactory`, for example an R2DBC connection pool.

      The `ConnectionFactory` passed in here needs to return independent `Connection`s. The `Connection`s typically come from a connection pool but the `ConnectionFactory` must not return specifically scoped or constrained `Connection`s.

    - #### getConnectionFactory

          @Nullable
          public io.r2dbc.spi.ConnectionFactory getConnectionFactory()

      Return the R2DBC `ConnectionFactory` that this instance manages transactions for.

    - #### obtainConnectionFactory

          protected io.r2dbc.spi.ConnectionFactory obtainConnectionFactory()

      Obtain the `ConnectionFactory` for actual use.
      Returns:
        the `ConnectionFactory` (never `null`)
      Throws:
        `IllegalStateException` - in case of no ConnectionFactory set

    - #### setEnforceReadOnly

          public void setEnforceReadOnly(boolean enforceReadOnly)

      Specify whether to enforce the read-only nature of a transaction (as indicated by `TransactionDefinition.isReadOnly()`) through an explicit statement on the transactional connection: "SET TRANSACTION READ ONLY" as understood by Oracle, MySQL and Postgres.

      The exact treatment, including any SQL statement executed on the connection, can be customized through `prepareTransactionalConnection(io.r2dbc.spi.Connection, org.springframework.transaction.TransactionDefinition, java.lang.Object)`.

      See Also:
        `prepareTransactionalConnection(io.r2dbc.spi.Connection, org.springframework.transaction.TransactionDefinition, java.lang.Object)`

    - #### isEnforceReadOnly

          public boolean isEnforceReadOnly()

      Return whether to enforce the read-only nature of a transaction through an explicit statement on the transactional connection.
      See Also:
        `setEnforceReadOnly(boolean)`

    - #### afterPropertiesSet

          public void afterPropertiesSet()

      Description copied from interface: `InitializingBean`
      Invoked by the containing `BeanFactory` after it has set all bean properties and satisfied `BeanFactoryAware`, `ApplicationContextAware` etc.

      This method allows the bean instance to perform validation of its overall configuration and final initialization when all bean properties have been set.

      Specified by:
        `afterPropertiesSet` in interface `InitializingBean`

    - #### doGetTransaction

          protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager)

      Description copied from class: `AbstractReactiveTransactionManager`
      Return a transaction object for the current transaction state.

      The returned object will usually be specific to the concrete transaction manager implementation, carrying corresponding transaction state in a modifiable fashion. This object will be passed into the other template methods (e.g. doBegin and doCommit), either directly or as part of a DefaultReactiveTransactionStatus instance.

      The returned object should contain information about any existing transaction, that is, a transaction that has already started before the current `getTransaction` call on the transaction manager. Consequently, a `doGetTransaction` implementation will usually look for an existing transaction and store corresponding state in the returned transaction object.

      Specified by:
        `doGetTransaction` in class `AbstractReactiveTransactionManager`
      Parameters:
        `synchronizationManager` - the synchronization manager bound to the current transaction
      Returns:
        the current transaction object
      See Also:
        `AbstractReactiveTransactionManager.doBegin(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object, org.springframework.transaction.TransactionDefinition)`, `AbstractReactiveTransactionManager.doCommit(org.springframework.transaction.reactive.TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction)`, `AbstractReactiveTransactionManager.doRollback(org.springframework.transaction.reactive.TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction)`, `GenericReactiveTransaction.getTransaction()`

    - #### isExistingTransaction

          protected boolean isExistingTransaction(Object transaction)

      Description copied from class: `AbstractReactiveTransactionManager`
      Check if the given transaction object indicates an existing transaction (that is, a transaction which has already started).

      The result will be evaluated according to the specified propagation behavior for the new transaction. An existing transaction might get suspended (in case of PROPAGATION_REQUIRES_NEW), or the new transaction might participate in the existing one (in case of PROPAGATION_REQUIRED).

      The default implementation returns `false`, assuming that participating in existing transactions is generally not supported. Subclasses are of course encouraged to provide such support.

      Overrides:
        `isExistingTransaction` in class `AbstractReactiveTransactionManager`
      Parameters:
        `transaction` - the transaction object returned by doGetTransaction
      Returns:
        if there is an existing transaction
      See Also:
        `AbstractReactiveTransactionManager.doGetTransaction(org.springframework.transaction.reactive.TransactionSynchronizationManager)`

    - #### doBegin

          protected reactor.core.publisher.Mono<Void> doBegin(TransactionSynchronizationManager synchronizationManager,
                                                              Object transaction,
                                                              TransactionDefinition definition)

      Description copied from class: `AbstractReactiveTransactionManager`
      Begin a new transaction with semantics according to the given transaction definition. Does not have to care about applying the propagation behavior, as this has already been handled by this abstract manager.

      This method gets called when the transaction manager has decided to actually start a new transaction. Either there wasn't any transaction before, or the previous transaction has been suspended.

      A special scenario is a nested transaction: This method will be called to start a nested transaction when necessary. In such a context, there will be an active transaction: The implementation of this method has to detect this and start an appropriate nested transaction.

      Specified by:
        `doBegin` in class `AbstractReactiveTransactionManager`
      Parameters:
        `synchronizationManager` - the synchronization manager bound to the new transaction
        `transaction` - the transaction object returned by `doGetTransaction`
        `definition` - a TransactionDefinition instance, describing propagation behavior, isolation level, read-only flag, timeout, and transaction name

    - #### determineTimeout

          protected Duration determineTimeout(TransactionDefinition definition)

      Determine the actual timeout to use for the given definition. Will fall back to this manager's default timeout if the transaction definition doesn't specify a non-default value.
      Parameters:
        `definition` - the transaction definition
      Returns:
        the actual timeout to use
      See Also:
        `TransactionDefinition.getTimeout()`

    - #### doSuspend

          protected reactor.core.publisher.Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager,
                                                                  Object transaction)

      Description copied from class: `AbstractReactiveTransactionManager`
      Suspend the resources of the current transaction. Transaction synchronization will already have been suspended.

      The default implementation throws a TransactionSuspensionNotSupportedException, assuming that transaction suspension is generally not supported.

      Overrides:
        `doSuspend` in class `AbstractReactiveTransactionManager`
      Parameters:
        `synchronizationManager` - the synchronization manager bound to the current transaction
        `transaction` - the transaction object returned by `doGetTransaction`
      Returns:
        an object that holds suspended resources (will be kept unexamined for passing it into doResume)
      See Also:
        `AbstractReactiveTransactionManager.doResume(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object, java.lang.Object)`

    - #### doResume

          protected reactor.core.publisher.Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager,
                                                               @Nullable
                                                               Object transaction,
                                                               Object suspendedResources)

      Description copied from class: `AbstractReactiveTransactionManager`
      Resume the resources of the current transaction. Transaction synchronization will be resumed afterwards.

      The default implementation throws a TransactionSuspensionNotSupportedException, assuming that transaction suspension is generally not supported.

      Overrides:
        `doResume` in class `AbstractReactiveTransactionManager`
      Parameters:
        `synchronizationManager` - the synchronization manager bound to the current transaction
        `transaction` - the transaction object returned by `doGetTransaction`
        `suspendedResources` - the object that holds suspended resources, as returned by doSuspend
      See Also:
        `AbstractReactiveTransactionManager.doSuspend(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object)`

    - #### doCommit

          protected reactor.core.publisher.Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynchronizationManager,
                                                               GenericReactiveTransaction status)

      Description copied from class: `AbstractReactiveTransactionManager`
      Perform an actual commit of the given transaction.

      An implementation does not need to check the "new transaction" flag or the rollback-only flag; this will already have been handled before. Usually, a straight commit will be performed on the transaction object contained in the passed-in status.

      Specified by:
        `doCommit` in class `AbstractReactiveTransactionManager`
      Parameters:
        `TransactionSynchronizationManager` - the synchronization manager bound to the current transaction
        `status` - the status representation of the transaction
      See Also:
        `GenericReactiveTransaction.getTransaction()`

    - #### doRollback

          protected reactor.core.publisher.Mono<Void> doRollback(TransactionSynchronizationManager TransactionSynchronizationManager,
                                                                 GenericReactiveTransaction status)

      Description copied from class: `AbstractReactiveTransactionManager`
      Perform an actual rollback of the given transaction.

      An implementation does not need to check the "new transaction" flag; this will already have been handled before. Usually, a straight rollback will be performed on the transaction object contained in the passed-in status.

      Specified by:
        `doRollback` in class `AbstractReactiveTransactionManager`
      Parameters:
        `TransactionSynchronizationManager` - the synchronization manager bound to the current transaction
        `status` - the status representation of the transaction
      See Also:
        `GenericReactiveTransaction.getTransaction()`

    - #### doSetRollbackOnly

          protected reactor.core.publisher.Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
                                                                        GenericReactiveTransaction status)

      Description copied from class: `AbstractReactiveTransactionManager`
      Set the given transaction rollback-only. Only called on rollback if the current transaction participates in an existing one.

      The default implementation throws an IllegalTransactionStateException, assuming that participating in existing transactions is generally not supported. Subclasses are of course encouraged to provide such support.

      Overrides:
        `doSetRollbackOnly` in class `AbstractReactiveTransactionManager`
      Parameters:
        `synchronizationManager` - the synchronization manager bound to the current transaction
        `status` - the status representation of the transaction

    - #### doCleanupAfterCompletion

          protected reactor.core.publisher.Mono<Void> doCleanupAfterCompletion(TransactionSynchronizationManager synchronizationManager,
                                                                               Object transaction)

      Description copied from class: `AbstractReactiveTransactionManager`
      Cleanup resources after transaction completion.

      Called after `doCommit` and `doRollback` execution, on any outcome. The default implementation does nothing.

      Should not throw any exceptions but just issue warnings on errors.

      Overrides:
        `doCleanupAfterCompletion` in class `AbstractReactiveTransactionManager`
      Parameters:
        `synchronizationManager` - the synchronization manager bound to the current transaction
        `transaction` - the transaction object returned by `doGetTransaction`

    - #### prepareTransactionalConnection

          @Deprecated
          protected reactor.core.publisher.Mono<Void> prepareTransactionalConnection(io.r2dbc.spi.Connection con,
                                                                                                 TransactionDefinition definition,
                                                                                                 Object transaction)

      Deprecated. in favor of `prepareTransactionalConnection(Connection, TransactionDefinition)` since this variant gets called too early (before transaction begin) for read-only customization
      Prepare the transactional `Connection` right before transaction begin.

    - #### prepareTransactionalConnection

          protected reactor.core.publisher.Mono<Void> prepareTransactionalConnection(io.r2dbc.spi.Connection con,
                                                                                     TransactionDefinition definition)

      Prepare the transactional `Connection` right after transaction begin.

      The default implementation executes a "SET TRANSACTION READ ONLY" statement if the `"enforceReadOnly"` flag is set to `true` and the transaction definition indicates a read-only transaction.

      The "SET TRANSACTION READ ONLY" is understood by Oracle, MySQL and Postgres and may work with other databases as well. If you'd like to adapt this treatment, override this method accordingly.

      Parameters:
        `con` - the transactional R2DBC Connection
        `definition` - the current transaction definition
      Since:
        5.3.22
      See Also:
        `setEnforceReadOnly(boolean)`

    - #### resolveIsolationLevel

          @Nullable
          protected io.r2dbc.spi.IsolationLevel resolveIsolationLevel(int isolationLevel)

      Resolve the isolation level constant to a R2DBC `IsolationLevel`. If you'd like to extend isolation level translation for vendor-specific `IsolationLevel`s, override this method accordingly.
      Parameters:
        `isolationLevel` - the isolation level to translate.
      Returns:
        the resolved isolation level. Can be `null` if not resolvable or the isolation level should remain `default`.
      See Also:
        `TransactionDefinition.getIsolationLevel()`

    - #### translateException

          protected RuntimeException translateException(String task,
                                                        io.r2dbc.spi.R2dbcException ex)

      Translate the given R2DBC commit/rollback exception to a common Spring exception to propagate from the `AbstractReactiveTransactionManager.commit(org.springframework.transaction.ReactiveTransaction)`/`AbstractReactiveTransactionManager.rollback(org.springframework.transaction.ReactiveTransaction)` call.
      Parameters:
        `task` - the task description (commit or rollback).
        `ex` - the SQLException thrown from commit/rollback.
      Returns:
        the translated exception to emit