@@ -184,7 +184,7 @@ transaction management. The following listing shows the definition of the
184
184
@Throws(TransactionException::class)
185
185
fun rollback(status: TransactionStatus)
186
186
}
187
- ----
187
+ ----
188
188
189
189
This is primarily a service provider interface (SPI), although you can use it
190
190
<<transaction-programmatic-ptm, programmatically>> from your application code. Because
@@ -241,7 +241,7 @@ listing shows the transaction strategy defined by
241
241
@Throws(TransactionException::class)
242
242
fun rollback(status: ReactiveTransaction): Mono<Void>
243
243
}
244
- ----
244
+ ----
245
245
246
246
The reactive transaction manager is primarily a service provider interface (SPI),
247
247
although you can use it <<transaction-programmatic-rtm, programmatically>> from your
@@ -566,7 +566,7 @@ abstractions mentioned earlier.
566
566
567
567
568
568
[[transaction-declarative]]
569
- === Declarative transaction management
569
+ === Declarative Transaction Management
570
570
571
571
NOTE: Most Spring Framework users choose declarative transaction management. This option has
572
572
the least impact on application code and, hence, is most consistent with the ideals of a
@@ -637,7 +637,7 @@ around method invocations.
637
637
638
638
NOTE: Spring AOP is covered in <<core.adoc#aop, the AOP section>>.
639
639
640
- Spring Frameworks 's `TransactionInterceptor` provides transaction management for
640
+ Spring Framework 's `TransactionInterceptor` provides transaction management for
641
641
imperative and reactive programming models. The interceptor detects the desired flavor of
642
642
transaction management by inspecting the method return type. Methods returning a reactive
643
643
type such as `Publisher` or Kotlin `Flow` (or a subtype of those) qualify for reactive
@@ -648,6 +648,18 @@ Transaction management flavors impact which transaction manager is required. Imp
648
648
transactions require a `PlatformTransactionManager`, while reactive transactions use
649
649
`ReactiveTransactionManager` implementations.
650
650
651
+ [NOTE]
652
+ ====
653
+ `@Transactional` commonly works with thread-bound transactions managed by
654
+ `PlatformTransactionManager`, exposing a transaction to all data access operations within
655
+ the current execution thread. Note: This does _not_ propagate to newly started threads
656
+ within the method.
657
+
658
+ A reactive transaction managed by `ReactiveTransactionManager` uses the Reactor context
659
+ instead of thread-local attributes. As a consequence, all participating data access
660
+ operations need to execute within the same Reactor context in the same reactive pipeline.
661
+ ====
662
+
651
663
The following image shows a conceptual view of calling a method on a transactional proxy:
652
664
653
665
image::images/tx.png[]
@@ -1737,7 +1749,7 @@ in the application context:
1737
1749
1738
1750
@Transactional("account")
1739
1751
public void doSomething() { ... }
1740
-
1752
+
1741
1753
@Transactional("reactive-account")
1742
1754
public Mono<Void> doSomethingReactive() { ... }
1743
1755
}
@@ -2442,7 +2454,7 @@ the `TransactionOperator` resembles the next example:
2442
2454
// the code in this method runs in a transactional context
2443
2455
2444
2456
Mono<Object> update = updateOperation1();
2445
-
2457
+
2446
2458
return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
2447
2459
}
2448
2460
}
@@ -2529,7 +2541,7 @@ following example shows customization of the transactional settings for a specif
2529
2541
2530
2542
public SimpleService(ReactiveTransactionManager transactionManager) {
2531
2543
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
2532
-
2544
+
2533
2545
// the transaction settings can be set here explicitly if so desired
2534
2546
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
2535
2547
definition.setTimeout(30); // 30 seconds
@@ -2627,7 +2639,7 @@ following example shows how to do so:
2627
2639
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
2628
2640
2629
2641
Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);
2630
-
2642
+
2631
2643
reactiveTx.flatMap(status -> {
2632
2644
2633
2645
Mono<Object> tx = ...; // put your business logic here
@@ -2841,30 +2853,29 @@ specific to each technology.
2841
2853
2842
2854
Spring provides a convenient translation from technology-specific exceptions, such as
2843
2855
`SQLException` to its own exception class hierarchy, which has `DataAccessException` as
2844
- the root exception. These exceptions wrap the original exception so that there is never any
2845
- risk that you might lose any information about what might have gone wrong.
2856
+ the root exception. These exceptions wrap the original exception so that there is never
2857
+ any risk that you might lose any information about what might have gone wrong.
2846
2858
2847
2859
In addition to JDBC exceptions, Spring can also wrap JPA- and Hibernate-specific exceptions,
2848
- converting them to a set of focused runtime exceptions.
2849
- This lets you handle most non-recoverable persistence exceptions
2850
- in only the appropriate layers, without having annoying boilerplate
2851
- catch-and-throw blocks and exception declarations in your DAOs. (You can still trap
2852
- and handle exceptions anywhere you need to though.) As mentioned above, JDBC
2853
- exceptions (including database-specific dialects) are also converted to the same
2860
+ converting them to a set of focused runtime exceptions. This lets you handle most
2861
+ non-recoverable persistence exceptions in only the appropriate layers, without having
2862
+ annoying boilerplate catch-and-throw blocks and exception declarations in your DAOs.
2863
+ (You can still trap and handle exceptions anywhere you need to though.) As mentioned above,
2864
+ JDBC exceptions (including database-specific dialects) are also converted to the same
2854
2865
hierarchy, meaning that you can perform some operations with JDBC within a consistent
2855
2866
programming model.
2856
2867
2857
- The preceding discussion holds true for the various template classes in Spring's support for various ORM
2858
- frameworks. If you use the interceptor-based classes, the application must care
2859
- about handling `HibernateExceptions` and `PersistenceExceptions` itself, preferably by
2860
- delegating to the `convertHibernateAccessException(..)` or
2861
- `convertJpaAccessException()` methods, respectively, of `SessionFactoryUtils`. These methods convert the exceptions
2868
+ The preceding discussion holds true for the various template classes in Spring's support
2869
+ for various ORM frameworks. If you use the interceptor-based classes, the application must
2870
+ care about handling `HibernateExceptions` and `PersistenceExceptions` itself, preferably by
2871
+ delegating to the `convertHibernateAccessException(..)` or `convertJpaAccessException(..)`
2872
+ methods, respectively, of `SessionFactoryUtils`. These methods convert the exceptions
2862
2873
to exceptions that are compatible with the exceptions in the `org.springframework.dao`
2863
- exception hierarchy. As `PersistenceExceptions` are unchecked, they can get
2864
- thrown, too (sacrificing generic DAO abstraction in terms of exceptions, though).
2874
+ exception hierarchy. As `PersistenceExceptions` are unchecked, they can get thrown, too
2875
+ (sacrificing generic DAO abstraction in terms of exceptions, though).
2865
2876
2866
- The following image shows the exception hierarchy that Spring provides. (Note that the
2867
- class hierarchy detailed in the image shows only a subset of the entire
2877
+ The following image shows the exception hierarchy that Spring provides.
2878
+ (Note that the class hierarchy detailed in the image shows only a subset of the entire
2868
2879
`DataAccessException` hierarchy.)
2869
2880
2870
2881
image::images/DataAccessException.png[]
@@ -2989,7 +3000,7 @@ this `DataSource`. The following example autowires a `DataSource`:
2989
3000
----
2990
3001
@Repository
2991
3002
class JdbcMovieFinder(dataSource: DataSource) : MovieFinder {
2992
-
3003
+
2993
3004
private val jdbcTemplate = JdbcTemplate(dataSource)
2994
3005
2995
3006
// ...
@@ -3250,8 +3261,8 @@ The following query finds and populates a single domain object:
3250
3261
----
3251
3262
val actor = jdbcTemplate.queryForObject(
3252
3263
"select first_name, last_name from t_actor where id = ?",
3253
- arrayOf(1212L)) { rs, _ ->
3254
- Actor(rs.getString("first_name"), rs.getString("last_name"))
3264
+ arrayOf(1212L)) { rs, _ ->
3265
+ Actor(rs.getString("first_name"), rs.getString("last_name"))
3255
3266
}
3256
3267
----
3257
3268
@@ -3503,7 +3514,7 @@ method with `@Autowired`. The following example shows how to do so:
3503
3514
class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao { // <2>
3504
3515
3505
3516
private val jdbcTemplate = JdbcTemplate(dataSource) // <3>
3506
-
3517
+
3507
3518
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
3508
3519
}
3509
3520
----
@@ -3842,10 +3853,10 @@ translator:
3842
3853
private val jdbcTemplate = JdbcTemplate(dataSource).apply {
3843
3854
// create a custom translator and set the DataSource for the default translation lookup
3844
3855
exceptionTranslator = CustomSQLErrorCodesTranslator().apply {
3845
- this.dataSource = dataSource
3856
+ this.dataSource = dataSource
3846
3857
}
3847
3858
}
3848
-
3859
+
3849
3860
fun updateShippingCharge(orderId: Long, pct: Long) {
3850
3861
// use the prepared JdbcTemplate for this update
3851
3862
this.jdbcTemplate!!.update("update orders" +
@@ -4069,8 +4080,8 @@ on Oracle but may not work on other platforms:
4069
4080
val name = "Rob"
4070
4081
4071
4082
val keyHolder = GeneratedKeyHolder()
4072
- jdbcTemplate.update({
4073
- it.prepareStatement (INSERT_SQL, arrayOf("id")).apply { setString(1, name) }
4083
+ jdbcTemplate.update({
4084
+ it.prepareStatement (INSERT_SQL, arrayOf("id")).apply { setString(1, name) }
4074
4085
}, keyHolder)
4075
4086
4076
4087
// keyHolder.getKey() now contains the generated key
@@ -4229,14 +4240,14 @@ interface that wraps a single `Connection` that is not closed after each use.
4229
4240
This is not multi-threading capable.
4230
4241
4231
4242
If any client code calls `close` on the assumption of a pooled connection (as when using
4232
- persistence tools), you should set the `suppressClose` property to `true`. This setting returns a
4233
- close-suppressing proxy that wraps the physical connection. Note that you can no longer
4234
- cast this to a native Oracle `Connection` or a similar object.
4243
+ persistence tools), you should set the `suppressClose` property to `true`. This setting
4244
+ returns a close-suppressing proxy that wraps the physical connection. Note that you can
4245
+ no longer cast this to a native Oracle `Connection` or a similar object.
4235
4246
4236
- `SingleConnectionDataSource` is primarily a test class. For example, it enables easy testing of code outside an
4237
- application server, in conjunction with a simple JNDI environment. In contrast to
4238
- `DriverManagerDataSource`, it reuses the same connection all the time, avoiding
4239
- excessive creation of physical connections.
4247
+ `SingleConnectionDataSource` is primarily a test class. It typically enables easy testing
4248
+ of code outside an application server, in conjunction with a simple JNDI environment.
4249
+ In contrast to `DriverManagerDataSource`, it reuses the same connection all the time,
4250
+ avoiding excessive creation of physical connections.
4240
4251
4241
4252
4242
4253
@@ -5008,7 +5019,7 @@ the constructor of your `SimpleJdbcCall`. The following example shows this confi
5008
5019
private var procReadActor = SimpleJdbcCall(JdbcTemplate(dataSource).apply {
5009
5020
isResultsMapCaseInsensitive = true
5010
5021
}).withProcedureName("read_actor")
5011
-
5022
+
5012
5023
// ... additional methods
5013
5024
}
5014
5025
----
@@ -5766,7 +5777,7 @@ the supplied `ResultSet`, as follows:
5766
5777
import org.springframework.jdbc.core.RowMapper
5767
5778
5768
5779
class GenreMapper : RowMapper<Genre> {
5769
-
5780
+
5770
5781
override fun mapRow(rs: ResultSet, rowNum: Int): Genre {
5771
5782
return Genre(rs.getString("name"))
5772
5783
}
@@ -6777,7 +6788,7 @@ chapter then cover the other ORM technologies and show brief examples.
6777
6788
NOTE: As of Spring Framework 5.0, Spring requires Hibernate ORM 4.3 or later for JPA support
6778
6789
and even Hibernate ORM 5.0+ for programming against the native Hibernate Session API.
6779
6790
Note that the Hibernate team does not maintain any versions prior to 5.1 anymore and
6780
- is likely to focus on 5.3 + exclusively soon.
6791
+ is likely to focus on 5.4 + exclusively soon.
6781
6792
6782
6793
6783
6794
[[orm-session-factory-setup]]
@@ -6884,7 +6895,7 @@ implementation resembles the following example, based on the plain Hibernate API
6884
6895
.Kotlin
6885
6896
----
6886
6897
class ProductDaoImpl(private val sessionFactory: SessionFactory) : ProductDao {
6887
-
6898
+
6888
6899
fun loadProductsByCategory(category: String): Collection<*> {
6889
6900
return sessionFactory.currentSession
6890
6901
.createQuery("from test.Product product where product.category=?")
@@ -7092,7 +7103,7 @@ and an example for a business method implementation:
7092
7103
----
7093
7104
class ProductServiceImpl(transactionManager: PlatformTransactionManager,
7094
7105
private val productDao: ProductDao) : ProductService {
7095
-
7106
+
7096
7107
private val transactionTemplate = TransactionTemplate(transactionManager)
7097
7108
7098
7109
fun increasePriceOfAllProductsInCategory(category: String) {
@@ -7354,7 +7365,7 @@ This includes web containers such as Tomcat, stand-alone applications, and
7354
7365
integration tests with sophisticated persistence requirements.
7355
7366
7356
7367
NOTE: If you want to specifically configure a Hibernate setup, an immediate alternative is
7357
- to go with Hibernate 5.2 or 5.3 and set up a native Hibernate `LocalSessionFactoryBean`
7368
+ to go with Hibernate 5.2/ 5.3/5.4 and set up a native Hibernate `LocalSessionFactoryBean`
7358
7369
instead of a plain JPA `LocalContainerEntityManagerFactoryBean`, letting it interact
7359
7370
with JPA access code as well as native Hibernate access code.
7360
7371
See <<orm-jpa-hibernate, Native Hibernate setup for JPA interaction>> for details.
@@ -7726,7 +7737,7 @@ Spring provides dialects for the EclipseLink and Hibernate JPA implementations.
7726
7737
See the <<orm-jpa-dialect, next section>> for details on the `JpaDialect` mechanism.
7727
7738
7728
7739
NOTE: As an immediate alternative, Spring's native `HibernateTransactionManager` is capable
7729
- of interacting with JPA access code as of Spring Framework 5.1 and Hibernate 5.2/5.3,
7740
+ of interacting with JPA access code as of Spring Framework 5.1 and Hibernate 5.2/5.3/5.4 ,
7730
7741
adapting to several Hibernate specifics and providing JDBC interaction.
7731
7742
This makes particular sense in combination with `LocalSessionFactoryBean` setup.
7732
7743
See <<orm-jpa-hibernate, Native Hibernate Setup for JPA Interaction>> for details.
@@ -7801,7 +7812,7 @@ less portable) but is set up for the server's JTA environment.
7801
7812
[[orm-jpa-hibernate]]
7802
7813
==== Native Hibernate Setup and Native Hibernate Transactions for JPA Interaction
7803
7814
7804
- As of Spring Framework 5.1 and Hibernate 5.2/5.3, a native `LocalSessionFactoryBean`
7815
+ As of Spring Framework 5.1 and Hibernate 5.2/5.3/5.4 , a native `LocalSessionFactoryBean`
7805
7816
setup in combination with `HibernateTransactionManager` allows for interaction with
7806
7817
`@PersistenceContext` and other JPA access code. A Hibernate
7807
7818
`SessionFactory` natively implements JPA's `EntityManagerFactory` interface now
@@ -8160,8 +8171,8 @@ can do so by using the following `applicationContext.xml`:
8160
8171
----
8161
8172
8162
8173
This application context uses XStream, but we could have used any of the other marshaller
8163
- instances described later in this chapter. Note that, by default, XStream does not require any further
8164
- configuration, so the bean definition is rather simple. Also note that the
8174
+ instances described later in this chapter. Note that, by default, XStream does not require
8175
+ any further configuration, so the bean definition is rather simple. Also note that the
8165
8176
`XStreamMarshaller` implements both `Marshaller` and `Unmarshaller`, so we can refer to the
8166
8177
`xstreamMarshaller` bean in both the `marshaller` and `unmarshaller` property of the
8167
8178
application.
@@ -8179,8 +8190,8 @@ This sample application produces the following `settings.xml` file:
8179
8190
[[oxm-schema-based-config]]
8180
8191
=== XML Configuration Namespace
8181
8192
8182
- You can configure marshallers more concisely by using tags from the OXM namespace. To
8183
- make these tags available, you must first reference the appropriate schema in the
8193
+ You can configure marshallers more concisely by using tags from the OXM namespace.
8194
+ To make these tags available, you must first reference the appropriate schema in the
8184
8195
preamble of the XML configuration file. The following example shows how to do so:
8185
8196
8186
8197
[source,xml,indent=0]
@@ -8423,7 +8434,7 @@ vulnerabilities do not get invoked.
8423
8434
8424
8435
NOTE: Note that XStream is an XML serialization library, not a data binding library.
8425
8436
Therefore, it has limited namespace support. As a result, it is rather unsuitable for usage
8426
- within Web services .
8437
+ within Web Services .
8427
8438
8428
8439
8429
8440
0 commit comments