Skip to content

Commit c5771bc

Browse files
committed
Discuss JdbcTransactionManager vs DataSourceTransactionManager
Includes doc update for 6.0 default exception translation etc. Closes gh-30802
1 parent 2365581 commit c5771bc

File tree

9 files changed

+105
-85
lines changed

9 files changed

+105
-85
lines changed

framework-docs/modules/ROOT/pages/data-access/dao.adoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,10 @@ Kotlin::
151151
----
152152
======
153153

154-
The last example we show here is for typical JDBC support. You could have the
155-
`DataSource` injected into an initialization method or a constructor, where you would create a
156-
`JdbcTemplate` and other data access support classes (such as `SimpleJdbcCall` and others) by using
157-
this `DataSource`. The following example autowires a `DataSource`:
154+
The last example we show here is for typical JDBC support. You could have the `DataSource`
155+
injected into an initialization method or a constructor, where you would create a `JdbcTemplate`
156+
and other data access support classes (such as `SimpleJdbcCall` and others) by using this
157+
`DataSource`. The following example autowires a `DataSource`:
158158

159159
[tabs]
160160
======

framework-docs/modules/ROOT/pages/data-access/jdbc/advanced.adoc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ to the database.
99
[[jdbc-batch-classic]]
1010
== Basic Batch Operations with `JdbcTemplate`
1111

12-
You accomplish `JdbcTemplate` batch processing by implementing two methods of a special
13-
interface, `BatchPreparedStatementSetter`, and passing that implementation in as the second parameter
12+
You accomplish `JdbcTemplate` batch processing by implementing two methods of a special interface,
13+
`BatchPreparedStatementSetter`, and passing that implementation in as the second parameter
1414
in your `batchUpdate` method call. You can use the `getBatchSize` method to provide the size of
1515
the current batch. You can use the `setValues` method to set the values for the parameters of
16-
the prepared statement. This method is called the number of times that you
17-
specified in the `getBatchSize` call. The following example updates the `t_actor` table
18-
based on entries in a list, and the entire list is used as the batch:
16+
the prepared statement. This method is called the number of times that you specified in the
17+
`getBatchSize` call. The following example updates the `t_actor` table based on entries in a list,
18+
and the entire list is used as the batch:
1919

2020
[tabs]
2121
======

framework-docs/modules/ROOT/pages/data-access/jdbc/connections.adoc

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This section covers:
1010
* xref:data-access/jdbc/connections.adoc#jdbc-SingleConnectionDataSource[Using `SingleConnectionDataSource`]
1111
* xref:data-access/jdbc/connections.adoc#jdbc-DriverManagerDataSource[Using `DriverManagerDataSource`]
1212
* xref:data-access/jdbc/connections.adoc#jdbc-TransactionAwareDataSourceProxy[Using `TransactionAwareDataSourceProxy`]
13-
* xref:data-access/jdbc/connections.adoc#jdbc-DataSourceTransactionManager[Using `DataSourceTransactionManager`]
13+
* xref:data-access/jdbc/connections.adoc#jdbc-DataSourceTransactionManager[Using `DataSourceTransactionManager` / `JdbcTransactionManager`]
1414

1515

1616
[[jdbc-datasource]]
@@ -125,8 +125,12 @@ The following example shows C3P0 configuration:
125125
== Using `DataSourceUtils`
126126

127127
The `DataSourceUtils` class is a convenient and powerful helper class that provides
128-
`static` methods to obtain connections from JNDI and close connections if necessary. It
129-
supports thread-bound connections with, for example, `DataSourceTransactionManager`.
128+
`static` methods to obtain connections from JNDI and close connections if necessary.
129+
It supports a thread-bound JDBC `Connection` with `DataSourceTransactionManager` but
130+
also with `JtaTransactionManager` and `JpaTransactionManager`.
131+
132+
Note that `JdbcTemplate` implies `DataSourceUtils` connection access, using it
133+
behind every JDBC operation, implicitly participating in an ongoing transaction.
130134

131135

132136
[[jdbc-SmartDataSource]]
@@ -165,7 +169,6 @@ In contrast to `DriverManagerDataSource`, it reuses the same connection all the
165169
avoiding excessive creation of physical connections.
166170

167171

168-
169172
[[jdbc-DriverManagerDataSource]]
170173
== Using `DriverManagerDataSource`
171174

@@ -201,29 +204,44 @@ javadoc for more details.
201204

202205

203206
[[jdbc-DataSourceTransactionManager]]
204-
== Using `DataSourceTransactionManager`
207+
== Using `DataSourceTransactionManager` / `JdbcTransactionManager`
205208

206209
The `DataSourceTransactionManager` class is a `PlatformTransactionManager`
207-
implementation for single JDBC data sources. It binds a JDBC connection from the
208-
specified data source to the currently executing thread, potentially allowing for one
209-
thread connection per data source.
210+
implementation for a single JDBC `DataSource`. It binds a JDBC `Connection`
211+
from the specified `DataSource` to the currently executing thread, potentially
212+
allowing for one thread-bound `Connection` per `DataSource`.
210213

211-
Application code is required to retrieve the JDBC connection through
212-
`DataSourceUtils.getConnection(DataSource)` instead of Jakarta EE's standard
214+
Application code is required to retrieve the JDBC `Connection` through
215+
`DataSourceUtils.getConnection(DataSource)` instead of Java EE's standard
213216
`DataSource.getConnection`. It throws unchecked `org.springframework.dao` exceptions
214-
instead of checked `SQLExceptions`. All framework classes (such as `JdbcTemplate`) use this
215-
strategy implicitly. If not used with this transaction manager, the lookup strategy
216-
behaves exactly like the common one. Thus, it can be used in any case.
217-
218-
The `DataSourceTransactionManager` class supports custom isolation levels and timeouts
219-
that get applied as appropriate JDBC statement query timeouts. To support the latter,
220-
application code must either use `JdbcTemplate` or call the
221-
`DataSourceUtils.applyTransactionTimeout(..)` method for each created statement.
222-
223-
You can use this implementation instead of `JtaTransactionManager` in the single-resource
224-
case, as it does not require the container to support JTA. Switching between
225-
both is just a matter of configuration, provided you stick to the required connection lookup
226-
pattern. JTA does not support custom isolation levels.
217+
instead of checked `SQLExceptions`. All framework classes (such as `JdbcTemplate`) use
218+
this strategy implicitly. If not used with a transaction manager, the lookup strategy
219+
behaves exactly like `DataSource.getConnection` and can therefore be used in any case.
220+
221+
The `DataSourceTransactionManager` class supports savepoints (`PROPAGATION_NESTED`),
222+
custom isolation levels, and timeouts that get applied as appropriate JDBC statement
223+
query timeouts. To support the latter, application code must either use `JdbcTemplate` or
224+
call the `DataSourceUtils.applyTransactionTimeout(..)` method for each created statement.
225+
226+
You can use `DataSourceTransactionManager` instead of `JtaTransactionManager` in the
227+
single-resource case, as it does not require the container to support a JTA transaction
228+
coordinator. Switching between these transaction managers is just a matter of configuration,
229+
provided you stick to the required connection lookup pattern. Note that JTA does not support
230+
savepoints or custom isolation levels and has a different timeout mechanism but otherwise
231+
exposes similar behavior in terms of JDBC resources and JDBC commit/rollback management.
232+
233+
NOTE: As of 5.3, Spring provides an extended `JdbcTransactionManager` variant which adds
234+
exception translation capabilities on commit/rollback (aligned with `JdbcTemplate`).
235+
Where `DataSourceTransactionManager` will only ever throw `TransactionSystemException`
236+
(analogous to JTA), `JdbcTransactionManager` translates database locking failures etc to
237+
corresponding `DataAccessException` subclasses. Note that application code needs to be
238+
prepared for such exceptions, not exclusively expecting `TransactionSystemException`.
239+
In scenarios where that is the case, `JdbcTransactionManager` is the recommended choice.
240+
241+
In terms of exception behavior, `JdbcTransactionManager` is roughly equivalent to
242+
`JpaTransactionManager` and also to `R2dbcTransactionManager`, serving as an immediate
243+
companion/replacement for each other. `DataSourceTransactionManager` on the other hand
244+
is equivalent to `JtaTransactionManager` and can serve as a direct replacement there.
227245

228246

229247

framework-docs/modules/ROOT/pages/data-access/jdbc/core.adoc

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -718,12 +718,22 @@ See also xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate-idioms[`JdbcTemplate`
718718
between ``SQLException``s and Spring's own `org.springframework.dao.DataAccessException`,
719719
which is agnostic in regard to data access strategy. Implementations can be generic (for
720720
example, using SQLState codes for JDBC) or proprietary (for example, using Oracle error
721-
codes) for greater precision.
721+
codes) for greater precision. This exception translation mechanism is used behind the
722+
the common `JdbcTemplate` and `JdbcTransactionManager` entry points which do not
723+
propagate `SQLException` but rather `DataAccessException`.
724+
725+
NOTE: As of 6.0, the default exception translator is `SQLExceptionSubclassTranslator`,
726+
detecting JDBC 4 `SQLException` subclasses with a few extra checks, and with a fallback
727+
to `SQLState` introspection through `SQLStateSQLExceptionTranslator`. This is usually
728+
sufficient for common database access and does not require vendor-specific detection.
729+
For backwards compatibility, consider using `SQLErrorCodeSQLExceptionTranslator` as
730+
described below, potentially with custom error code mappings.
722731

723732
`SQLErrorCodeSQLExceptionTranslator` is the implementation of `SQLExceptionTranslator`
724-
that is used by default. This implementation uses specific vendor codes. It is more
725-
precise than the `SQLState` implementation. The error code translations are based on
726-
codes held in a JavaBean type class called `SQLErrorCodes`. This class is created and
733+
that is used by default when a file named `sql-error-codes.xml` is present in the root
734+
of the classpath. This implementation uses specific vendor codes. It is more precise than
735+
`SQLState` or `SQLException` subclass translation. The error code translations are based
736+
on codes held in a JavaBean type class called `SQLErrorCodes`. This class is created and
727737
populated by an `SQLErrorCodesFactory`, which (as the name suggests) is a factory for
728738
creating `SQLErrorCodes` based on the contents of a configuration file named
729739
`sql-error-codes.xml`. This file is populated with vendor codes and based on the
@@ -744,8 +754,8 @@ The `SQLErrorCodeSQLExceptionTranslator` applies matching rules in the following
744754
translator. If this translation is not available, the next fallback translator is
745755
the `SQLStateSQLExceptionTranslator`.
746756

747-
NOTE: The `SQLErrorCodesFactory` is used by default to define `Error` codes and custom exception
748-
translations. They are looked up in a file named `sql-error-codes.xml` from the
757+
NOTE: The `SQLErrorCodesFactory` is used by default to define error codes and custom
758+
exception translations. They are looked up in a file named `sql-error-codes.xml` from the
749759
classpath, and the matching `SQLErrorCodes` instance is located based on the database
750760
name from the database metadata of the database in use.
751761

@@ -784,12 +794,12 @@ Kotlin::
784794
----
785795
======
786796

787-
In the preceding example, the specific error code (`-12345`) is translated, while other errors are
788-
left to be translated by the default translator implementation. To use this custom
789-
translator, you must pass it to the `JdbcTemplate` through the method
790-
`setExceptionTranslator`, and you must use this `JdbcTemplate` for all of the data access
791-
processing where this translator is needed. The following example shows how you can use this custom
792-
translator:
797+
In the preceding example, the specific error code (`-12345`) is translated while
798+
other errors are left to be translated by the default translator implementation.
799+
To use this custom translator, you must pass it to the `JdbcTemplate` through the
800+
method `setExceptionTranslator`, and you must use this `JdbcTemplate` for all of the
801+
data access processing where this translator is needed. The following example shows
802+
how you can use this custom translator:
793803

794804
[tabs]
795805
======
@@ -800,7 +810,6 @@ Java::
800810
private JdbcTemplate jdbcTemplate;
801811
802812
public void setDataSource(DataSource dataSource) {
803-
804813
// create a JdbcTemplate and set data source
805814
this.jdbcTemplate = new JdbcTemplate();
806815
this.jdbcTemplate.setDataSource(dataSource);
@@ -809,7 +818,6 @@ Java::
809818
CustomSQLErrorCodesTranslator tr = new CustomSQLErrorCodesTranslator();
810819
tr.setDataSource(dataSource);
811820
this.jdbcTemplate.setExceptionTranslator(tr);
812-
813821
}
814822
815823
public void updateShippingCharge(long orderId, long pct) {

framework-docs/modules/ROOT/pages/data-access/jdbc/packages.adoc

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@
33

44
The Spring Framework's JDBC abstraction framework consists of four different packages:
55

6-
* `core`: The `org.springframework.jdbc.core` package contains the `JdbcTemplate` class and its
7-
various callback interfaces, plus a variety of related classes. A subpackage named
8-
`org.springframework.jdbc.core.simple` contains the `SimpleJdbcInsert` and
6+
* `core`: The `org.springframework.jdbc.core` package contains the `JdbcTemplate` class
7+
and its various callback interfaces, plus a variety of related classes. A subpackage
8+
named `org.springframework.jdbc.core.simple` contains the `SimpleJdbcInsert` and
99
`SimpleJdbcCall` classes. Another subpackage named
1010
`org.springframework.jdbc.core.namedparam` contains the `NamedParameterJdbcTemplate`
1111
class and the related support classes. See xref:data-access/jdbc/core.adoc[Using the JDBC Core Classes to Control Basic JDBC Processing and Error Handling], xref:data-access/jdbc/advanced.adoc[JDBC Batch Operations], and
1212
xref:data-access/jdbc/simple.adoc[Simplifying JDBC Operations with the `SimpleJdbc` Classes].
1313

14-
* `datasource`: The `org.springframework.jdbc.datasource` package contains a utility class for easy
15-
`DataSource` access and various simple `DataSource` implementations that you can use for
16-
testing and running unmodified JDBC code outside of a Jakarta EE container. A subpackage
17-
named `org.springfamework.jdbc.datasource.embedded` provides support for creating
14+
* `datasource`: The `org.springframework.jdbc.datasource` package contains a utility class
15+
for easy `DataSource` access and various simple `DataSource` implementations that you can
16+
use for testing and running unmodified JDBC code outside of a Jakarta EE container. A subpackage
17+
named `org.springframework.jdbc.datasource.embedded` provides support for creating
1818
embedded databases by using Java database engines, such as HSQL, H2, and Derby. See
1919
xref:data-access/jdbc/connections.adoc[Controlling Database Connections] and xref:data-access/jdbc/embedded-database-support.adoc[Embedded Database Support].
2020

21-
* `object`: The `org.springframework.jdbc.object` package contains classes that represent RDBMS
22-
queries, updates, and stored procedures as thread-safe, reusable objects. See
21+
* `object`: The `org.springframework.jdbc.object` package contains classes that represent
22+
RDBMS queries, updates, and stored procedures as thread-safe, reusable objects. See
2323
xref:data-access/jdbc/object.adoc[Modeling JDBC Operations as Java Objects]. This approach is modeled by JDO, although objects returned by queries
2424
are naturally disconnected from the database. This higher-level of JDBC abstraction
2525
depends on the lower-level abstraction in the `org.springframework.jdbc.core` package.
2626

27-
* `support`: The `org.springframework.jdbc.support` package provides `SQLException` translation
28-
functionality and some utility classes. Exceptions thrown during JDBC processing are
29-
translated to exceptions defined in the `org.springframework.dao` package. This means
27+
* `support`: The `org.springframework.jdbc.support` package provides `SQLException`
28+
translation functionality and some utility classes. Exceptions thrown during JDBC processing
29+
are translated to exceptions defined in the `org.springframework.dao` package. This means
3030
that code using the Spring JDBC abstraction layer does not need to implement JDBC or
3131
RDBMS-specific error handling. All translated exceptions are unchecked, which gives you
3232
the option of catching the exceptions from which you can recover while letting other

framework-docs/modules/ROOT/pages/data-access/orm/jpa.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ features supported by Spring, usually in a vendor-specific manner:
495495
* Applying specific transaction semantics (such as custom isolation level or transaction
496496
timeout)
497497
* Retrieving the transactional JDBC `Connection` (for exposure to JDBC-based DAOs)
498-
* Advanced translation of `PersistenceExceptions` to Spring `DataAccessExceptions`
498+
* Advanced translation of `PersistenceException` to Spring's `DataAccessException`
499499

500500
This is particularly valuable for special transaction semantics and for advanced
501501
translation of exception. The default implementation (`DefaultJpaDialect`) does

framework-docs/modules/ROOT/pages/data-access/r2dbc.adoc

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -718,19 +718,15 @@ javadoc for more details.
718718
=== Using `R2dbcTransactionManager`
719719

720720
The `R2dbcTransactionManager` class is a `ReactiveTransactionManager` implementation for
721-
single R2DBC data sources. It binds an R2DBC connection from the specified connection factory
722-
to the subscriber `Context`, potentially allowing for one subscriber connection for each
723-
connection factory.
721+
a single R2DBC `ConnectionFactory`. It binds an R2DBC `Connection` from the specified
722+
`ConnectionFactory` to the subscriber `Context`, potentially allowing for one subscriber
723+
`Connection` for each `ConnectionFactory`.
724724

725-
Application code is required to retrieve the R2DBC connection through
725+
Application code is required to retrieve the R2DBC `Connection` through
726726
`ConnectionFactoryUtils.getConnection(ConnectionFactory)`, instead of R2DBC's standard
727-
`ConnectionFactory.create()`.
728-
729-
All framework classes (such as `DatabaseClient`) use this strategy implicitly.
730-
If not used with this transaction manager, the lookup strategy behaves exactly like the common one.
731-
Thus, it can be used in any case.
732-
733-
The `R2dbcTransactionManager` class supports custom isolation levels that get applied to the connection.
727+
`ConnectionFactory.create()`. All framework classes (such as `DatabaseClient`) use this
728+
strategy implicitly. If not used with a transaction manager, the lookup strategy behaves
729+
exactly like `ConnectionFactory.create()` and can therefore be used in any case.
734730

735731

736732

framework-docs/modules/ROOT/pages/data-access/transaction/declarative/annotations.adoc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ In XML configuration, the `<tx:annotation-driven/>` tag provides similar conveni
124124
----
125125
<1> The line that makes the bean instance transactional.
126126

127-
128127
TIP: You can omit the `transaction-manager` attribute in the `<tx:annotation-driven/>`
129128
tag if the bean name of the `TransactionManager` that you want to wire in has the name
130129
`transactionManager`. If the `TransactionManager` bean that you want to dependency-inject
@@ -522,17 +521,17 @@ The following listing shows the bean declarations:
522521
----
523522
<tx:annotation-driven/>
524523
525-
<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
524+
<bean id="transactionManager1" class="org.springframework.jdbc.support.JdbcTransactionManager">
526525
...
527526
<qualifier value="order"/>
528527
</bean>
529528
530-
<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
529+
<bean id="transactionManager2" class="org.springframework.jdbc.support.JdbcTransactionManager">
531530
...
532531
<qualifier value="account"/>
533532
</bean>
534533
535-
<bean id="transactionManager3" class="org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager">
534+
<bean id="transactionManager3" class="org.springframework.data.r2dbc.connection.R2dbcTransactionManager">
536535
...
537536
<qualifier value="reactive-account"/>
538537
</bean>

0 commit comments

Comments
 (0)