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 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
.
Constructor and Description |
---|
R2dbcTransactionManager()
Create a new @link ConnectionFactoryTransactionManager} instance.
|
R2dbcTransactionManager(io.r2dbc.spi.ConnectionFactory connectionFactory)
Create a new
R2dbcTransactionManager instance. |
Modifier and Type | Method and Description |
---|---|
void |
afterPropertiesSet() |
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) |
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) |
protected io.r2dbc.spi.ConnectionFactory |
obtainConnectionFactory()
Obtain the
ConnectionFactory for actual use. |
protected reactor.core.publisher.Mono<Void> |
prepareTransactionalConnection(io.r2dbc.spi.Connection con,
org.springframework.transaction.TransactionDefinition definition,
Object transaction)
Prepare the transactional
Connection right after transaction begin. |
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. |
public R2dbcTransactionManager()
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 connection pool.
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
s or the like.
TransactionAwareConnectionFactoryProxy
@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 through prepareTransactionalConnection(io.r2dbc.spi.Connection, org.springframework.transaction.TransactionDefinition, java.lang.Object)
.
public boolean isEnforceReadOnly()
setEnforceReadOnly(boolean)
public void afterPropertiesSet()
afterPropertiesSet
in interface org.springframework.beans.factory.InitializingBean
protected Object doGetTransaction(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager) throws org.springframework.transaction.TransactionException
doGetTransaction
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.transaction.TransactionException
protected boolean isExistingTransaction(Object transaction)
isExistingTransaction
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
protected reactor.core.publisher.Mono<Void> doBegin(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction, org.springframework.transaction.TransactionDefinition definition) throws org.springframework.transaction.TransactionException
doBegin
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.transaction.TransactionException
protected Duration determineTimeout(org.springframework.transaction.TransactionDefinition definition)
definition
- the transaction definitionTransactionDefinition.getTimeout()
protected reactor.core.publisher.Mono<Object> doSuspend(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction) throws org.springframework.transaction.TransactionException
doSuspend
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.transaction.TransactionException
protected reactor.core.publisher.Mono<Void> doResume(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, @Nullable Object transaction, Object suspendedResources) throws org.springframework.transaction.TransactionException
doResume
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.transaction.TransactionException
protected reactor.core.publisher.Mono<Void> doCommit(org.springframework.transaction.reactive.TransactionSynchronizationManager TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status) throws org.springframework.transaction.TransactionException
doCommit
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.transaction.TransactionException
protected reactor.core.publisher.Mono<Void> doRollback(org.springframework.transaction.reactive.TransactionSynchronizationManager TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status) throws org.springframework.transaction.TransactionException
doRollback
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.transaction.TransactionException
protected reactor.core.publisher.Mono<Void> doSetRollbackOnly(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction status) throws org.springframework.transaction.TransactionException
doSetRollbackOnly
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
org.springframework.transaction.TransactionException
protected reactor.core.publisher.Mono<Void> doCleanupAfterCompletion(org.springframework.transaction.reactive.TransactionSynchronizationManager synchronizationManager, Object transaction)
doCleanupAfterCompletion
in class org.springframework.transaction.reactive.AbstractReactiveTransactionManager
protected reactor.core.publisher.Mono<Void> prepareTransactionalConnection(io.r2dbc.spi.Connection con, org.springframework.transaction.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 io.r2dbc.spi.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.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.