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.
AbstractReactiveTransactionManager.SuspendedResourcesHolder
logger
Constructor and Description |
---|
R2dbcTransactionManager()
Create a new
R2dbcTransactionManager instance. |
R2dbcTransactionManager(io.r2dbc.spi.ConnectionFactory connectionFactory)
Create a new
R2dbcTransactionManager instance. |
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. |
commit, getReactiveTransaction, prepareForCommit, registerAfterCompletionWithExistingTransaction, rollback
public R2dbcTransactionManager()
R2dbcTransactionManager
instance.
A ConnectionFactory
has to be set to be able to use it.public R2dbcTransactionManager(io.r2dbc.spi.ConnectionFactory connectionFactory)
R2dbcTransactionManager
instance.connectionFactory
- the R2DBC ConnectionFactory to manage transactions forpublic void setConnectionFactory(@Nullable io.r2dbc.spi.ConnectionFactory connectionFactory)
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.
@Nullable public io.r2dbc.spi.ConnectionFactory getConnectionFactory()
ConnectionFactory
that this instance manages transactions for.protected io.r2dbc.spi.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 prepareTransactionalConnection(io.r2dbc.spi.Connection, org.springframework.transaction.TransactionDefinition, java.lang.Object)
.
public boolean isEnforceReadOnly()
setEnforceReadOnly(boolean)
public void afterPropertiesSet()
InitializingBean
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.
afterPropertiesSet
in interface InitializingBean
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager)
AbstractReactiveTransactionManager
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.
doGetTransaction
in class AbstractReactiveTransactionManager
synchronizationManager
- the synchronization manager bound to the current transactionAbstractReactiveTransactionManager.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()
protected boolean isExistingTransaction(Object transaction)
AbstractReactiveTransactionManager
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.
isExistingTransaction
in class AbstractReactiveTransactionManager
transaction
- the transaction object returned by doGetTransactionAbstractReactiveTransactionManager.doGetTransaction(org.springframework.transaction.reactive.TransactionSynchronizationManager)
protected reactor.core.publisher.Mono<Void> doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction, TransactionDefinition definition)
AbstractReactiveTransactionManager
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.
doBegin
in class AbstractReactiveTransactionManager
synchronizationManager
- the synchronization manager bound to the new transactiontransaction
- the transaction object returned by doGetTransaction
definition
- a TransactionDefinition instance, describing propagation
behavior, isolation level, read-only flag, timeout, and transaction nameprotected Duration determineTimeout(TransactionDefinition definition)
definition
- the transaction definitionTransactionDefinition.getTimeout()
protected reactor.core.publisher.Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction)
AbstractReactiveTransactionManager
The default implementation throws a TransactionSuspensionNotSupportedException, assuming that transaction suspension is generally not supported.
doSuspend
in class AbstractReactiveTransactionManager
synchronizationManager
- the synchronization manager bound to the current transactiontransaction
- the transaction object returned by doGetTransaction
AbstractReactiveTransactionManager.doResume(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object, java.lang.Object)
protected reactor.core.publisher.Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager, @Nullable Object transaction, Object suspendedResources)
AbstractReactiveTransactionManager
The default implementation throws a TransactionSuspensionNotSupportedException, assuming that transaction suspension is generally not supported.
doResume
in class AbstractReactiveTransactionManager
synchronizationManager
- the synchronization manager bound to the current transactiontransaction
- the transaction object returned by doGetTransaction
suspendedResources
- the object that holds suspended resources,
as returned by doSuspendAbstractReactiveTransactionManager.doSuspend(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object)
protected reactor.core.publisher.Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynchronizationManager, GenericReactiveTransaction status)
AbstractReactiveTransactionManager
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.
doCommit
in class AbstractReactiveTransactionManager
TransactionSynchronizationManager
- the synchronization manager bound to the current transactionstatus
- the status representation of the transactionGenericReactiveTransaction.getTransaction()
protected reactor.core.publisher.Mono<Void> doRollback(TransactionSynchronizationManager TransactionSynchronizationManager, GenericReactiveTransaction status)
AbstractReactiveTransactionManager
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.
doRollback
in class AbstractReactiveTransactionManager
TransactionSynchronizationManager
- the synchronization manager bound to the current transactionstatus
- the status representation of the transactionGenericReactiveTransaction.getTransaction()
protected reactor.core.publisher.Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager, GenericReactiveTransaction status)
AbstractReactiveTransactionManager
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.
doSetRollbackOnly
in class AbstractReactiveTransactionManager
synchronizationManager
- the synchronization manager bound to the current transactionstatus
- the status representation of the transactionprotected reactor.core.publisher.Mono<Void> doCleanupAfterCompletion(TransactionSynchronizationManager synchronizationManager, Object transaction)
AbstractReactiveTransactionManager
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.
doCleanupAfterCompletion
in class AbstractReactiveTransactionManager
synchronizationManager
- the synchronization manager bound to the current transactiontransaction
- the transaction object returned by doGetTransaction
@Deprecated protected reactor.core.publisher.Mono<Void> prepareTransactionalConnection(io.r2dbc.spi.Connection con, TransactionDefinition definition, Object transaction)
prepareTransactionalConnection(Connection, TransactionDefinition)
since this variant gets called too early (before transaction begin) for read-only customizationConnection
right before transaction begin.protected reactor.core.publisher.Mono<Void> prepareTransactionalConnection(io.r2dbc.spi.Connection con, TransactionDefinition definition)
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 definitionsetEnforceReadOnly(boolean)
@Nullable protected io.r2dbc.spi.IsolationLevel resolveIsolationLevel(int isolationLevel)
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.null
if not resolvable or the isolation level
should remain default
.TransactionDefinition.getIsolationLevel()
protected RuntimeException translateException(String task, io.r2dbc.spi.R2dbcException ex)
AbstractReactiveTransactionManager.commit(org.springframework.transaction.ReactiveTransaction)
/AbstractReactiveTransactionManager.rollback(org.springframework.transaction.ReactiveTransaction)
call.task
- the task description (commit or rollback).ex
- the SQLException thrown from commit/rollback.