Class R2dbcTransactionManager

java.lang.Object
org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.r2dbc.connection.R2dbcTransactionManager
All Implemented Interfaces:
Serializable, org.springframework.beans.factory.InitializingBean, org.springframework.transaction.ConfigurableTransactionManager, org.springframework.transaction.ReactiveTransactionManager, org.springframework.transaction.TransactionManager

public class R2dbcTransactionManager extends org.springframework.transaction.reactive.AbstractReactiveTransactionManager implements org.springframework.beans.factory.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 Connections. The Connections typically come from a connection pool but the ConnectionFactory must not return specifically scoped or constrained Connections. 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.

Spring's TransactionDefinition attributes are carried forward to R2DBC drivers using extensible R2DBC TransactionDefinition. Subclasses may override createTransactionDefinition(TransactionDefinition) to customize transaction definitions for vendor-specific attributes. As of 6.0.10, this transaction manager supports nested transactions via R2DBC savepoints as well.

Since:
5.3
Author:
Mark Paluch, Juergen Hoeller
See Also:
  • Nested Class Summary

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

    org.springframework.transaction.reactive.AbstractReactiveTransactionManager.SuspendedResourcesHolder
  • Field Summary

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

    logger
  • Constructor Summary

    Constructors
    Constructor
    Description
    Create a new R2dbcTransactionManager instance.
    Create a new R2dbcTransactionManager instance.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
     
    createTransactionDefinition(org.springframework.transaction.TransactionDefinition definition)
    Determine the transaction definition from our TransactionDefinition.
    protected Duration
    determineTimeout(org.springframework.transaction.TransactionDefinition definition)
    Determine the actual timeout to use for the given definition.
    protected reactor.core.publisher.Mono<Void>
    doBegin(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction, org.springframework.transaction.TransactionDefinition definition)
     
    protected reactor.core.publisher.Mono<Void>
    doCleanupAfterCompletion(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction)
     
    protected reactor.core.publisher.Mono<Void>
    doCommit(org.springframework.transaction.reactive.TransactionSynchronizationManager TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status)
     
    protected Object
    doGetTransaction(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager)
     
    protected reactor.core.publisher.Mono<Void>
    doResume(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction, Object suspendedResources)
     
    protected reactor.core.publisher.Mono<Void>
    doRollback(org.springframework.transaction.reactive.TransactionSynchronizationManager TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status)
     
    protected reactor.core.publisher.Mono<Void>
    doSetRollbackOnly(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status)
     
    protected reactor.core.publisher.Mono<Object>
    doSuspend(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction)
     
    Return the R2DBC ConnectionFactory that this instance manages transactions for.
    boolean
    Return whether to enforce the read-only nature of a transaction through an explicit statement on the transactional connection.
    protected boolean
     
    Obtain the ConnectionFactory for actual use.
    protected reactor.core.publisher.Mono<Void>
    prepareTransactionalConnection(Connection con, org.springframework.transaction.TransactionDefinition definition)
    Prepare the transactional Connection right after transaction begin.
    protected IsolationLevel
    resolveIsolationLevel(int isolationLevel)
    Resolve the isolation level constant to a R2DBC IsolationLevel.
    void
    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.
    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, getTransactionExecutionListeners, prepareForCommit, registerAfterCompletionWithExistingTransaction, rollback, setTransactionExecutionListeners

    Methods inherited from class java.lang.Object

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

    Methods inherited from interface org.springframework.transaction.ConfigurableTransactionManager

    addListener
  • Constructor Details

    • R2dbcTransactionManager

      public R2dbcTransactionManager()
      Create a new R2dbcTransactionManager instance. A ConnectionFactory has to be set to be able to use it.
      See Also:
    • R2dbcTransactionManager

      public R2dbcTransactionManager(ConnectionFactory connectionFactory)
      Create a new R2dbcTransactionManager instance.
      Parameters:
      connectionFactory - the R2DBC ConnectionFactory to manage transactions for
  • Method Details

    • setConnectionFactory

      public void setConnectionFactory(@Nullable 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 Connections. The Connections typically come from a connection pool but the ConnectionFactory must not return specifically scoped or constrained Connections.

    • getConnectionFactory

      @Nullable public ConnectionFactory getConnectionFactory()
      Return the R2DBC ConnectionFactory that this instance manages transactions for.
    • obtainConnectionFactory

      protected 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).

      See Also:
    • 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:
    • afterPropertiesSet

      public void afterPropertiesSet()
      Specified by:
      afterPropertiesSet in interface org.springframework.beans.factory.InitializingBean
    • doGetTransaction

      protected Object doGetTransaction(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager)
      Specified by:
      doGetTransaction in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • isExistingTransaction

      protected boolean isExistingTransaction(Object transaction)
      Overrides:
      isExistingTransaction in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • doBegin

      protected reactor.core.publisher.Mono<Void> doBegin(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction, org.springframework.transaction.TransactionDefinition definition)
      Specified by:
      doBegin in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • createTransactionDefinition

      protected TransactionDefinition createTransactionDefinition(org.springframework.transaction.TransactionDefinition definition)
      Determine the transaction definition from our TransactionDefinition. Can be overridden to wrap the R2DBC TransactionDefinition to adjust or enhance transaction attributes.
      Parameters:
      definition - the transaction definition
      Returns:
      the actual transaction definition to use
      Since:
      6.0
      See Also:
    • determineTimeout

      protected Duration determineTimeout(org.springframework.transaction.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(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction)
      Overrides:
      doSuspend in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • doResume

      protected reactor.core.publisher.Mono<Void> doResume(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, @Nullable Object transaction, Object suspendedResources)
      Overrides:
      doResume in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • doCommit

      protected reactor.core.publisher.Mono<Void> doCommit(org.springframework.transaction.reactive.TransactionSynchronizationManager TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status)
      Specified by:
      doCommit in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • doRollback

      protected reactor.core.publisher.Mono<Void> doRollback(org.springframework.transaction.reactive.TransactionSynchronizationManager TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status)
      Specified by:
      doRollback in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • doSetRollbackOnly

      protected reactor.core.publisher.Mono<Void> doSetRollbackOnly(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status)
      Overrides:
      doSetRollbackOnly in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • doCleanupAfterCompletion

      protected reactor.core.publisher.Mono<Void> doCleanupAfterCompletion(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction)
      Overrides:
      doCleanupAfterCompletion in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
    • prepareTransactionalConnection

      protected reactor.core.publisher.Mono<Void> prepareTransactionalConnection(Connection con, org.springframework.transaction.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:
    • resolveIsolationLevel

      @Nullable protected 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 IsolationLevels, 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, 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