Polish reactive transaction mgmt documentation in reference manual

See gh-25030
This commit is contained in:
Sam Brannen
2020-05-08 18:13:31 +02:00
parent 7fbdc3ad11
commit e1b2cafb33

View File

@@ -150,10 +150,13 @@ configuration file need to change (rather than your code).
[[transaction-strategies]] [[transaction-strategies]]
=== Understanding the Spring Framework Transaction Abstraction === Understanding the Spring Framework Transaction Abstraction
The key to the Spring transaction abstraction is the notion of a transaction The key to the Spring transaction abstraction is the notion of a transaction strategy. A
strategy. A transaction strategy is defined by a `TransactionManager`, specifically transaction strategy is defined by a `TransactionManager`, specifically the
the `org.springframework.transaction.PlatformTransactionManager` interface for `org.springframework.transaction.PlatformTransactionManager` interface for imperative
imperative transaction management which the following listing shows: transaction management and the
`org.springframework.transaction.ReactiveTransactionManager` interface for reactive
transaction management. The following listing shows the definition of the
`PlatformTransactionManager` API:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -189,8 +192,8 @@ This is primarily a service provider interface (SPI), although you can use it
necessary. It is not tied to a lookup strategy, such as JNDI. necessary. It is not tied to a lookup strategy, such as JNDI.
`PlatformTransactionManager` implementations are defined like any other object (or bean) `PlatformTransactionManager` implementations are defined like any other object (or bean)
in the Spring Framework IoC container. This benefit alone makes Spring Framework in the Spring Framework IoC container. This benefit alone makes Spring Framework
transactions a worthwhile abstraction, even when you work with JTA. You can test transactional code transactions a worthwhile abstraction, even when you work with JTA. You can test
much more easily than if it used JTA directly. transactional code much more easily than if it used JTA directly.
Again, in keeping with Spring's philosophy, the `TransactionException` that can be thrown Again, in keeping with Spring's philosophy, the `TransactionException` that can be thrown
by any of the `PlatformTransactionManager` interface's methods is unchecked (that by any of the `PlatformTransactionManager` interface's methods is unchecked (that
@@ -207,9 +210,9 @@ exists in the current call stack. The implication in this latter case is that, a
Java EE transaction contexts, a `TransactionStatus` is associated with a thread of Java EE transaction contexts, a `TransactionStatus` is associated with a thread of
execution. execution.
Spring Framework provides a transaction management abstraction for reactive applications As of Spring Framework 5.2, Spring also provides a transaction management abstraction for
that make use of reactive types or Kotlin Coroutines. The following listing reactive applications that make use of reactive types or Kotlin Coroutines. The following
shows the transaction strategy defined by listing shows the transaction strategy defined by
`org.springframework.transaction.ReactiveTransactionManager`: `org.springframework.transaction.ReactiveTransactionManager`:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
@@ -242,8 +245,8 @@ shows the transaction strategy defined by
The reactive transaction manager is primarily a service provider interface (SPI), The reactive transaction manager is primarily a service provider interface (SPI),
although you can use it <<transaction-programmatic-rtm, programmatically>> from your although you can use it <<transaction-programmatic-rtm, programmatically>> from your
application code. Because `ReactiveTransactionManager` is an interface, it can application code. Because `ReactiveTransactionManager` is an interface, it can be easily
be easily mocked or stubbed as necessary. mocked or stubbed as necessary.
The `TransactionDefinition` interface specifies: The `TransactionDefinition` interface specifies:
@@ -315,13 +318,13 @@ familiar, as they are common to all transaction APIs. The following listing show
---- ----
Regardless of whether you opt for declarative or programmatic transaction management in Regardless of whether you opt for declarative or programmatic transaction management in
Spring, defining the correct `TransactionManager` implementation is absolutely Spring, defining the correct `TransactionManager` implementation is absolutely essential.
essential. You typically define this implementation through dependency injection. You typically define this implementation through dependency injection.
`TransactionManager` implementations normally require knowledge of the `TransactionManager` implementations normally require knowledge of the environment in
environment in which they work: JDBC, JTA, Hibernate, and so on. The following examples which they work: JDBC, JTA, Hibernate, and so on. The following examples show how you can
show how you can define a local `PlatformTransactionManager` implementation (in this case, define a local `PlatformTransactionManager` implementation (in this case, with plain
with plain JDBC.) JDBC.)
You can define a JDBC `DataSource` by creating a bean similar to the following: You can define a JDBC `DataSource` by creating a bean similar to the following:
@@ -335,8 +338,8 @@ You can define a JDBC `DataSource` by creating a bean similar to the following:
</bean> </bean>
---- ----
The related `PlatformTransactionManager` bean definition then has a reference to The related `PlatformTransactionManager` bean definition then has a reference to the
the `DataSource` definition. It should resemble the following example: `DataSource` definition. It should resemble the following example:
[source,xml,indent=0,subs="verbatim,quotes"] [source,xml,indent=0,subs="verbatim,quotes"]
---- ----
@@ -346,8 +349,8 @@ the `DataSource` definition. It should resemble the following example:
---- ----
If you use JTA in a Java EE container, then you use a container `DataSource`, obtained If you use JTA in a Java EE container, then you use a container `DataSource`, obtained
through JNDI, in conjunction with Spring's `JtaTransactionManager`. The following example shows what the JTA through JNDI, in conjunction with Spring's `JtaTransactionManager`. The following example
and JNDI lookup version would look like: shows what the JTA and JNDI lookup version would look like:
[source,xml,indent=0,subs="verbatim,quotes"] [source,xml,indent=0,subs="verbatim,quotes"]
---- ----
@@ -378,21 +381,21 @@ NOTE: The preceding definition of the `dataSource` bean uses the `<jndi-lookup/>
from the `jee` namespace. For more information see from the `jee` namespace. For more information see
<<integration.adoc#xsd-schemas-jee, The JEE Schema>>. <<integration.adoc#xsd-schemas-jee, The JEE Schema>>.
You can also use easily Hibernate local transactions, as shown in the following You can also easily use Hibernate local transactions, as shown in the following examples.
examples. In this case, you need to define a Hibernate `LocalSessionFactoryBean`, In this case, you need to define a Hibernate `LocalSessionFactoryBean`, which your
which your application code can use to obtain Hibernate `Session` instances. application code can use to obtain Hibernate `Session` instances.
The `DataSource` bean definition is similar to the local JDBC example shown The `DataSource` bean definition is similar to the local JDBC example shown previously
previously and, thus, is not shown in the following example. and, thus, is not shown in the following example.
NOTE: If the `DataSource` (used by any non-JTA transaction manager) is looked up through NOTE: If the `DataSource` (used by any non-JTA transaction manager) is looked up through
JNDI and managed by a Java EE container, it should be non-transactional, because the JNDI and managed by a Java EE container, it should be non-transactional, because the
Spring Framework (rather than the Java EE container) manages the transactions. Spring Framework (rather than the Java EE container) manages the transactions.
The `txManager` bean in this case is of the `HibernateTransactionManager` type. In the The `txManager` bean in this case is of the `HibernateTransactionManager` type. In the
same way as the `DataSourceTransactionManager` needs a reference to the `DataSource`, same way as the `DataSourceTransactionManager` needs a reference to the `DataSource`, the
the `HibernateTransactionManager` needs a reference to the `SessionFactory`. `HibernateTransactionManager` needs a reference to the `SessionFactory`. The following
The following example declares `sessionFactory` and `txManager` beans: example declares `sessionFactory` and `txManager` beans:
[source,xml,indent=0,subs="verbatim,quotes"] [source,xml,indent=0,subs="verbatim,quotes"]
---- ----
@@ -415,9 +418,9 @@ The following example declares `sessionFactory` and `txManager` beans:
</bean> </bean>
---- ----
If you use Hibernate and Java EE container-managed JTA transactions, you If you use Hibernate and Java EE container-managed JTA transactions, you should use the
should use the same `JtaTransactionManager` as in the previous JTA example for same `JtaTransactionManager` as in the previous JTA example for JDBC, as the following
JDBC, as the following example shows: example shows:
[source,xml,indent=0,subs="verbatim,quotes"] [source,xml,indent=0,subs="verbatim,quotes"]
---- ----
@@ -459,7 +462,7 @@ synchronization of the resources, and exception mapping. Thus, user data access
not have to address these tasks but can focus purely on non-boilerplate not have to address these tasks but can focus purely on non-boilerplate
persistence logic. Generally, you use the native ORM API or take a template approach persistence logic. Generally, you use the native ORM API or take a template approach
for JDBC access by using the `JdbcTemplate`. These solutions are detailed in subsequent for JDBC access by using the `JdbcTemplate`. These solutions are detailed in subsequent
chapters of this reference documentation. sections of this reference documentation.
[[tx-resource-synchronization-low]] [[tx-resource-synchronization-low]]
@@ -576,32 +579,32 @@ on unchecked exceptions), it is often useful to customize this behavior.
It is not sufficient merely to tell you to annotate your classes with the It is not sufficient merely to tell you to annotate your classes with the
`@Transactional` annotation, add `@EnableTransactionManagement` to your configuration, `@Transactional` annotation, add `@EnableTransactionManagement` to your configuration,
and expect you to understand how it all works. To provide a deeper understanding, and expect you to understand how it all works. To provide a deeper understanding, this
this section explains the inner workings of the Spring Framework's declarative section explains the inner workings of the Spring Framework's declarative transaction
transaction infrastructure in the event of transaction-related issues. infrastructure in the context of transaction-related issues.
The most important concepts to grasp with regard to the Spring Framework's declarative The most important concepts to grasp with regard to the Spring Framework's declarative
transaction support are that this support is enabled transaction support are that this support is enabled
<<core.adoc#aop-understanding-aop-proxies, via AOP proxies>> and that the transactional <<core.adoc#aop-understanding-aop-proxies, via AOP proxies>> and that the transactional
advice is driven by metadata (currently XML- or annotation-based). The combination of advice is driven by metadata (currently XML- or annotation-based). The combination of AOP
AOP with transactional metadata yields an AOP proxy that uses a `TransactionInterceptor` with transactional metadata yields an AOP proxy that uses a `TransactionInterceptor` in
in conjunction with an appropriate `TransactionManager` implementation to drive conjunction with an appropriate `TransactionManager` implementation to drive transactions
transactions around method invocations. around method invocations.
NOTE: Spring AOP is covered in <<core.adoc#aop, the AOP section>>. NOTE: Spring AOP is covered in <<core.adoc#aop, the AOP section>>.
Spring Frameworks's `TransactionInterceptor` provides transaction management for imperative Spring Frameworks's `TransactionInterceptor` provides transaction management for
and reactive programming models. The interceptor detects the desired flavor of transaction imperative and reactive programming models. The interceptor detects the desired flavor of
management by inspecting the method return type. Methods returning a reactive type such transaction management by inspecting the method return type. Methods returning a reactive
as `Publisher` or Kotlin `Flow` (or a subtype of those) qualify for reactive transaction type such as `Publisher` or Kotlin `Flow` (or a subtype of those) qualify for reactive
management. All other return types including `void` use the code path for imperative transaction management. All other return types including `void` use the code path for
transaction management. imperative transaction management.
Transaction management flavors impacts which transaction manager required. Transaction management flavors impact which transaction manager is required. Imperative
Imperative transactions require a `PlatformTransactionManager` while reactive transactions transactions require a `PlatformTransactionManager`, while reactive transactions use
use `ReactiveTransactionManager` implementations. `ReactiveTransactionManager` implementations.
The following images shows a Conceptual view of calling a method on a transactional proxy: The following image shows a conceptual view of calling a method on a transactional proxy:
image::images/tx.png[] image::images/tx.png[]
@@ -614,8 +617,9 @@ Consider the following interface and its attendant implementation. This example
usage without focusing on a particular domain model. For the purposes of this example, usage without focusing on a particular domain model. For the purposes of this example,
the fact that the `DefaultFooService` class throws `UnsupportedOperationException` the fact that the `DefaultFooService` class throws `UnsupportedOperationException`
instances in the body of each implemented method is good. That behavior lets you see instances in the body of each implemented method is good. That behavior lets you see
transactions be created and then rolled back in response to the transactions being created and then rolled back in response to the
`UnsupportedOperationException` instance. The following listing shows the `FooService` interface: `UnsupportedOperationException` instance. The following listing shows the `FooService`
interface:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -771,14 +775,14 @@ configuration is explained in detail in the next few paragraphs:
</beans> </beans>
---- ----
Examine the preceding configuration. It assumes that you want to make a service object, the `fooService` Examine the preceding configuration. It assumes that you want to make a service object,
bean, transactional. The transaction semantics to apply are encapsulated in the the `fooService` bean, transactional. The transaction semantics to apply are encapsulated
`<tx:advice/>` definition. The `<tx:advice/>` definition reads as "`all methods, on in the `<tx:advice/>` definition. The `<tx:advice/>` definition reads as "all methods
starting with `get`, are to execute in the context of a read-only transaction, and all starting with `get` are to execute in the context of a read-only transaction, and all
other methods are to execute with the default transaction semantics`". The other methods are to execute with the default transaction semantics". The
`transaction-manager` attribute of the `<tx:advice/>` tag is set to the name of the `transaction-manager` attribute of the `<tx:advice/>` tag is set to the name of the
`TransactionManager` bean that is going to drive the transactions (in this `TransactionManager` bean that is going to drive the transactions (in this case, the
case, the `txManager` bean). `txManager` bean).
TIP: You can omit the `transaction-manager` attribute in the transactional advice TIP: You can omit the `transaction-manager` attribute in the transactional advice
(`<tx:advice/>`) if the bean name of the `TransactionManager` that you want to (`<tx:advice/>`) if the bean name of the `TransactionManager` that you want to
@@ -813,7 +817,7 @@ NOTE: In the preceding example, it is assumed that all your service interfaces a
in the `x.y.service` package. See <<core.adoc#aop, the AOP section>> for more details. in the `x.y.service` package. See <<core.adoc#aop, the AOP section>> for more details.
Now that we have analyzed the configuration, you may be asking yourself, Now that we have analyzed the configuration, you may be asking yourself,
"`What does all this configuration actually do?`" "What does all this configuration actually do?"
The configuration shown earlier is used to create a transactional proxy around the object The configuration shown earlier is used to create a transactional proxy around the object
that is created from the `fooService` bean definition. The proxy is configured with that is created from the `fooService` bean definition. The proxy is configured with
@@ -847,8 +851,8 @@ that test drives the configuration shown earlier:
---- ----
The output from running the preceding program should resemble the following (the Log4J The output from running the preceding program should resemble the following (the Log4J
output and the stack trace from the UnsupportedOperationException thrown by the output and the stack trace from the `UnsupportedOperationException` thrown by the
insertFoo(..) method of the DefaultFooService class have been truncated for clarity): `insertFoo(..)` method of the `DefaultFooService` class have been truncated for clarity):
[source,xml,indent=0,subs="verbatim,quotes"] [source,xml,indent=0,subs="verbatim,quotes"]
---- ----
@@ -882,10 +886,11 @@ insertFoo(..) method of the DefaultFooService class have been truncated for clar
To use reactive transaction management the code has to use reactive types. To use reactive transaction management the code has to use reactive types.
NOTES: Spring Framework uses `ReactiveAdapterRegistry` to determine whether a NOTE: Spring Framework uses the `ReactiveAdapterRegistry` to determine whether a method
method return type is reactive. return type is reactive.
The following listing shows the previously used `FooService` but this time the code is using reactive types: The following listing shows a modified version of the previously used `FooService`, but
this time the code uses reactive types:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -921,7 +926,7 @@ The following listing shows the previously used `FooService` but this time the c
fun insertFoo(foo: Foo) : Mono<Void> fun insertFoo(foo: Foo) : Mono<Void>
fun updateFoo(foo: Foo) fun updateFoo(foo: Foo) : Mono<Void>
} }
---- ----
@@ -980,27 +985,27 @@ The following example shows an implementation of the preceding interface:
} }
---- ----
Imperative and reactive transaction management shares the same semantics for Imperative and reactive transaction management share the same semantics for transaction
transaction boundary and transaction attribute definitions. The main difference boundary and transaction attribute definitions. The main difference between imperative
to imperative transactions is the deferred nature. `TransactionInterceptor` and reactive transactions is the deferred nature of the latter. `TransactionInterceptor`
decorates the returned reactive type with a transactional operator decorates the returned reactive type with a transactional operator to begin and clean up
to begin and cleanup the transaction. Therefore, calling a transactional the transaction. Therefore, calling a transactional reactive method defers the actual
reactive method defers the actual transaction management to subscription transaction management to a subscription type that activates processing of the reactive
type that activates processing of the reactive type. type.
Another aspect of reactive transaction management relates to data escaping Another aspect of reactive transaction management relates to data escaping which is a
which is a natural consequence of the programming model. natural consequence of the programming model.
Method return values of imperative transactions are returned from transactional methods Method return values of imperative transactions are returned from transactional methods
upon successful termination of a method so that partially computed results upon successful termination of a method so that partially computed results do not escape
do not escape the method closure. the method closure.
Reactive transaction methods return a reactive wrapper type which represent a Reactive transaction methods return a reactive wrapper type which represents a
computation sequence along with a promise to begin and complete computation. computation sequence along with a promise to begin and complete the computation.
A `Publisher` can emit data while an transaction is ongoing but not necessarily A `Publisher` can emit data while a transaction is ongoing but not necessarily completed.
completed. Therefore, methods that depend upon successful completion of an entire Therefore, methods that depend upon successful completion of an entire transaction need
transaction need to ensure completion and buffer results in the calling code. to ensure completion and buffer results in the calling code.
[[transaction-declarative-rolling-back]] [[transaction-declarative-rolling-back]]
@@ -1394,14 +1399,14 @@ In XML configuration, the `<tx:annotation-driven/>` tag provides similar conveni
<1> The line that makes the bean instance transactional. <1> The line that makes the bean instance transactional.
TIP: You can omit the `transaction-manager` attribute in the `<tx:annotation-driven/>` tag TIP: You can omit the `transaction-manager` attribute in the `<tx:annotation-driven/>`
if the bean name of the `PlatformTransactionManager` that you want to wire in has the name, tag if the bean name of the `TransactionManager` that you want to wire in has the name,
`transactionManager`. If the `TransactionManager` bean that you want to `transactionManager`. If the `TransactionManager` bean that you want to dependency-inject
dependency-inject has any other name, you have to use the `transaction-manager` attribute, has any other name, you have to use the `transaction-manager` attribute, as in the
as in the preceding example. preceding example.
Reactive transactional methods use reactive return types in contrast to imperative programming Reactive transactional methods use reactive return types in contrast to imperative
arrangements as the following listing shows: programming arrangements as the following listing shows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -1668,10 +1673,10 @@ Most Spring applications need only a single transaction manager, but there may b
situations where you want multiple independent transaction managers in a single situations where you want multiple independent transaction managers in a single
application. You can use the `value` or `transactionManager` attribute of the application. You can use the `value` or `transactionManager` attribute of the
`@Transactional` annotation to optionally specify the identity of the `@Transactional` annotation to optionally specify the identity of the
`TransactionManager` to be used. This can either be the bean name or the `TransactionManager` to be used. This can either be the bean name or the qualifier value
qualifier value of the transaction manager bean. For example, using the qualifier of the transaction manager bean. For example, using the qualifier notation, you can
notation, you can combine the following Java code with the following transaction manager combine the following Java code with the following transaction manager bean declarations
bean declarations in the application context: in the application context:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -1732,17 +1737,17 @@ The following listing shows the bean declarations:
</bean> </bean>
---- ----
In this case, the individual methods on `TransactionalService` run under separate transaction In this case, the individual methods on `TransactionalService` run under separate
managers, differentiated by the `order`, `account`, and `reactive-account` qualifiers. The default transaction managers, differentiated by the `order`, `account`, and `reactive-account`
`<tx:annotation-driven>` target bean name, `transactionManager`, is still used if no qualifiers. The default `<tx:annotation-driven>` target bean name, `transactionManager`,
specifically qualified `TransactionManager` bean is found. is still used if no specifically qualified `TransactionManager` bean is found.
[[tx-custom-attributes]] [[tx-custom-attributes]]
===== Custom Shortcut Annotations ===== Custom Composed Annotations
If you find you repeatedly use the same attributes with `@Transactional` on many different If you find you repeatedly use the same attributes with `@Transactional` on many different
methods, <<core.adoc#beans-meta-annotations, Spring's meta-annotation support>> lets you methods, <<core.adoc#beans-meta-annotations, Spring's meta-annotation support>> lets you
define custom shortcut annotations for your specific use cases. For example, consider the define custom composed annotations for your specific use cases. For example, consider the
following annotation definitions: following annotation definitions:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
@@ -1774,7 +1779,7 @@ following annotation definitions:
annotation class AccountTx annotation class AccountTx
---- ----
The preceding annotations lets us write the example from the previous section as follows: The preceding annotations let us write the example from the previous section as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -1809,8 +1814,9 @@ The preceding annotations lets us write the example from the previous section as
} }
---- ----
In the preceding example, we used the syntax to define the transaction manager qualifier, but we could also In the preceding example, we used the syntax to define the transaction manager qualifier,
have included propagation behavior, rollback rules, timeouts, and other features. but we could also have included propagation behavior, rollback rules, timeouts, and other
features.
[[tx-propagation]] [[tx-propagation]]
@@ -2165,8 +2171,8 @@ The Spring Framework provides two means of programmatic transaction management,
The Spring team generally recommends the `TransactionTemplate` for programmatic The Spring team generally recommends the `TransactionTemplate` for programmatic
transaction management in imperative flows and `TransactionalOperator` for reactive code. transaction management in imperative flows and `TransactionalOperator` for reactive code.
The second approach is similar to using the JTA The second approach is similar to using the JTA `UserTransaction` API, although exception
`UserTransaction` API, although exception handling is less cumbersome. handling is less cumbersome.
[[tx-prog-template]] [[tx-prog-template]]
@@ -2357,18 +2363,17 @@ two distinct `TransactionTemplate` instances.
==== Using the `TransactionOperator` ==== Using the `TransactionOperator`
The `TransactionOperator` follows an operator design that is similar to other reactive The `TransactionOperator` follows an operator design that is similar to other reactive
operators. It uses a callback approach (to free application code from having to operators. It uses a callback approach (to free application code from having to do the
do the boilerplate acquisition and release transactional resources) and results in boilerplate acquisition and release transactional resources) and results in code that is
code that is intention driven, in that your code focuses solely on what intention driven, in that your code focuses solely on what you want to do.
you want to do.
NOTE: As the examples that follow show, using the `TransactionOperator` absolutely NOTE: As the examples that follow show, using the `TransactionOperator` absolutely
couples you to Spring's transaction infrastructure and APIs. Whether or not programmatic couples you to Spring's transaction infrastructure and APIs. Whether or not programmatic
transaction management is suitable for your development needs is a decision that you transaction management is suitable for your development needs is a decision that you have
have to make yourself. to make yourself.
Application code that must execute in a transactional context and that explicitly uses the Application code that must execute in a transactional context and that explicitly uses
`TransactionOperator` resembles the next example: the `TransactionOperator` resembles the next example:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -2414,8 +2419,8 @@ Application code that must execute in a transactional context and that explicitl
* Operator-style using Project Reactor types (`mono.as(transactionalOperator::transactional)`) * Operator-style using Project Reactor types (`mono.as(transactionalOperator::transactional)`)
* Callback-style for every other case (`transactionalOperator.execute(TransactionCallback<T>)`) * Callback-style for every other case (`transactionalOperator.execute(TransactionCallback<T>)`)
Code within the callback can roll the transaction back by calling the Code within the callback can roll the transaction back by calling the `setRollbackOnly()`
`setRollbackOnly()` method on the supplied `TransactionStatus` object, as follows: method on the supplied `ReactiveTransaction` object, as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -2445,11 +2450,11 @@ Code within the callback can roll the transaction back by calling the
===== Specifying Transaction Settings ===== Specifying Transaction Settings
You can specify transaction settings (such as the propagation mode, the isolation level, You can specify transaction settings (such as the propagation mode, the isolation level,
the timeout, and so forth) for the `TransactionalOperator`. the timeout, and so forth) for the `TransactionalOperator`. By default,
By default, `TransactionalOperator` instances have the `TransactionalOperator` instances have
<<transaction-declarative-txadvice-settings,default transactional settings>>. The <<transaction-declarative-txadvice-settings,default transactional settings>>. The
following example shows customization of the transactional settings for following example shows customization of the transactional settings for a specific
a specific `TransactionalOperator:` `TransactionalOperator:`
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -2488,16 +2493,18 @@ a specific `TransactionalOperator:`
[[transaction-programmatic-tm]] [[transaction-programmatic-tm]]
==== Using the `TransactionManager` ==== Using the `TransactionManager`
The following section explains programmatic usage of imperative and reactive transaction managers. The following sections explain programmatic usage of imperative and reactive transaction
managers.
[[transaction-programmatic-ptm]] [[transaction-programmatic-ptm]]
===== Using the `PlatformTransactionManager` ===== Using the `PlatformTransactionManager`
For imperative transactions, you can use the `org.springframework.transaction.PlatformTransactionManager` For imperative transactions, you can use a
directly to manage your transaction. To do so, pass the implementation of the `org.springframework.transaction.PlatformTransactionManager` directly to manage your
`PlatformTransactionManager` you use to your bean through a bean reference. Then, transaction. To do so, pass the implementation of the `PlatformTransactionManager` you
by using the `TransactionDefinition` and `TransactionStatus` objects, you can initiate use to your bean through a bean reference. Then, by using the `TransactionDefinition` and
transactions, roll back, and commit. The following example shows how to do so: `TransactionStatus` objects, you can initiate transactions, roll back, and commit. The
following example shows how to do so:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java
@@ -2540,12 +2547,12 @@ transactions, roll back, and commit. The following example shows how to do so:
[[transaction-programmatic-rtm]] [[transaction-programmatic-rtm]]
===== Using the `ReactiveTransactionManager` ===== Using the `ReactiveTransactionManager`
When working with reactive transactions, you can use When working with reactive transactions, you can use a
`org.springframework.transaction.ReactiveTransactionManager` `org.springframework.transaction.ReactiveTransactionManager` directly to manage your
directly to manage your transaction. To do so, pass the implementation of the transaction. To do so, pass the implementation of the `ReactiveTransactionManager` you
`ReactiveTransactionManager` you use to your bean through a bean reference. Then, use to your bean through a bean reference. Then, by using the `TransactionDefinition` and
by using the `TransactionDefinition` and `ReactiveTransaction` objects, you can initiate `ReactiveTransaction` objects, you can initiate transactions, roll back, and commit. The
transactions, roll back, and commit. The following example shows how to do so: following example shows how to do so:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java