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 may come from a pool (the typical case), but the
ConnectionFactory
must not return scoped scoped Connection
s or the like. This transaction manager
will associate Connection
with context-bound transactions itself, 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 standard R2DBC lookup pattern
ConnectionFactory.create()
, for example for code that is not aware of Spring at all. 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.
This transaction manager triggers flush callbacks on registered transaction synchronizations (if synchronization is
generally active), assuming resources operating on the underlying R2DBC Connection
.
AbstractReactiveTransactionManager.SuspendedResourcesHolder
logger
Constructor and Description |
---|
R2dbcTransactionManager()
Create a new @link ConnectionFactoryTransactionManager} instance.
|
R2dbcTransactionManager(ConnectionFactory connectionFactory)
Create a new
R2dbcTransactionManager instance. |
Modifier and Type | Method and Description |
---|---|
void |
afterPropertiesSet() |
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) |
protected reactor.core.publisher.Mono<Void> |
doCleanupAfterCompletion(TransactionSynchronizationManager synchronizationManager,
Object transaction) |
protected reactor.core.publisher.Mono<Void> |
doCommit(TransactionSynchronizationManager TransactionSynchronizationManager,
GenericReactiveTransaction status) |
protected Object |
doGetTransaction(TransactionSynchronizationManager synchronizationManager) |
protected reactor.core.publisher.Mono<Void> |
doResume(TransactionSynchronizationManager synchronizationManager,
Object transaction,
Object suspendedResources) |
protected reactor.core.publisher.Mono<Void> |
doRollback(TransactionSynchronizationManager TransactionSynchronizationManager,
GenericReactiveTransaction status) |
protected reactor.core.publisher.Mono<Void> |
doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) |
protected reactor.core.publisher.Mono<Object> |
doSuspend(TransactionSynchronizationManager synchronizationManager,
Object transaction) |
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) |
protected ConnectionFactory |
obtainConnectionFactory()
Obtain the
ConnectionFactory for actual use. |
protected reactor.core.publisher.Mono<Void> |
prepareTransactionalConnection(Connection con,
TransactionDefinition definition,
Object transaction)
Prepare the transactional
Connection right after transaction begin. |
protected IsolationLevel |
resolveIsolationLevel(int isolationLevel)
Resolve the
isolation level constant to a R2DBC
IsolationLevel . |
void |
setConnectionFactory(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. |
void |
setExceptionTranslator(R2dbcExceptionTranslator exceptionTranslator)
Set the exception translator for this instance.
|
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. |
commit, getReactiveTransaction, prepareForCommit, registerAfterCompletionWithExistingTransaction, rollback
public R2dbcTransactionManager()
public R2dbcTransactionManager(ConnectionFactory connectionFactory)
R2dbcTransactionManager
instance.connectionFactory
- the R2DBC ConnectionFactory to manage transactions forpublic void setConnectionFactory(@Nullable ConnectionFactory connectionFactory)
ConnectionFactory
that this instance should manage transactions for.
This will typically be a locally defined ConnectionFactory
, for example an connection pool.
The ConnectionFactory
specified here should be the target ConnectionFactory
to manage transactions
for, not a TransactionAwareConnectionFactoryProxy. Only data access code may work with
TransactionAwareConnectionFactoryProxy, while the transaction manager needs to work on the underlying target
ConnectionFactory
. If there's nevertheless a TransactionAwareConnectionFactoryProxy passed in, it will be
unwrapped to extract its target ConnectionFactory
.
The ConnectionFactory
passed in here needs to return independent Connection
s. The
Connection
s may come from a pool (the typical case), but the ConnectionFactory
must not return
scoped Connection
or the like.
TransactionAwareConnectionFactoryProxy
@Nullable public ConnectionFactory getConnectionFactory()
ConnectionFactory
that this instance manages transactions for.public void setExceptionTranslator(R2dbcExceptionTranslator exceptionTranslator)
If no custom translator is provided, a default R2dbcExceptionSubclassTranslator
is used which translates
R2dbcException
's subclasses into Springs DataAccessException
hierarchy.
R2dbcExceptionSubclassTranslator
protected ConnectionFactory obtainConnectionFactory()
ConnectionFactory
for actual use.ConnectionFactory
(never null)IllegalStateException
- in case of no ConnectionFactory setpublic void setEnforceReadOnly(boolean enforceReadOnly)
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 through
prepareTransactionalConnection(io.r2dbc.spi.Connection, org.springframework.transaction.TransactionDefinition, java.lang.Object)
.
public boolean isEnforceReadOnly()
setEnforceReadOnly(boolean)
public void afterPropertiesSet()
afterPropertiesSet
in interface InitializingBean
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) throws TransactionException
doGetTransaction
in class AbstractReactiveTransactionManager
TransactionException
protected boolean isExistingTransaction(Object transaction)
isExistingTransaction
in class AbstractReactiveTransactionManager
protected reactor.core.publisher.Mono<Void> doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction, TransactionDefinition definition) throws TransactionException
doBegin
in class AbstractReactiveTransactionManager
TransactionException
protected Duration determineTimeout(TransactionDefinition definition)
definition
- the transaction definitionTransactionDefinition.getTimeout()
protected reactor.core.publisher.Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction) throws TransactionException
doSuspend
in class AbstractReactiveTransactionManager
TransactionException
protected reactor.core.publisher.Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager, Object transaction, Object suspendedResources) throws TransactionException
doResume
in class AbstractReactiveTransactionManager
TransactionException
protected reactor.core.publisher.Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynchronizationManager, GenericReactiveTransaction status) throws TransactionException
doCommit
in class AbstractReactiveTransactionManager
TransactionException
protected reactor.core.publisher.Mono<Void> doRollback(TransactionSynchronizationManager TransactionSynchronizationManager, GenericReactiveTransaction status) throws TransactionException
doRollback
in class AbstractReactiveTransactionManager
TransactionException
protected reactor.core.publisher.Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager, GenericReactiveTransaction status) throws TransactionException
doSetRollbackOnly
in class AbstractReactiveTransactionManager
TransactionException
protected reactor.core.publisher.Mono<Void> doCleanupAfterCompletion(TransactionSynchronizationManager synchronizationManager, Object transaction)
doCleanupAfterCompletion
in class AbstractReactiveTransactionManager
protected reactor.core.publisher.Mono<Void> prepareTransactionalConnection(Connection con, TransactionDefinition definition, Object transaction)
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.
con
- the transactional R2DBC Connectiondefinition
- the current transaction definitiontransaction
- the transaction objectsetEnforceReadOnly(boolean)
@Nullable protected IsolationLevel resolveIsolationLevel(int isolationLevel)
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.isolationLevel
- the isolation level to translate.default
.TransactionDefinition.getIsolationLevel()
protected RuntimeException translateException(String task, R2dbcException ex)
AbstractReactiveTransactionManager.commit(org.springframework.transaction.ReactiveTransaction)
/AbstractReactiveTransactionManager.rollback(org.springframework.transaction.ReactiveTransaction)
call.
The default implementation throws a TransactionSystemException
. Subclasses may specifically identify
concurrency failures etc.
task
- the task description (commit or rollback).ex
- the SQLException thrown from commit/rollback.DataAccessException
or a
TransactionException
Copyright © 2018–2021 Pivotal Software, Inc.. All rights reserved.