0% found this document useful (0 votes)
105 views25 pages

Data Access

Auto-detection is not implemented for remote interfaces. The main reason why auto-detection of implemented interfaces does not occur for remote interfaces is to avoid opening too many doors to remote callers. The target object might implement internal callback interfaces, such as InitializingBean or DisposableBean which one would not want to expose to callers.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
105 views25 pages

Data Access

Auto-detection is not implemented for remote interfaces. The main reason why auto-detection of implemented interfaces does not occur for remote interfaces is to avoid opening too many doors to remote callers. The target object might implement internal callback interfaces, such as InitializingBean or DisposableBean which one would not want to expose to callers.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

7/31/22, 5:50 PM Data Access

Data Access

Version 5.3.22

Back to index

1. Transaction Management
1.1. Advantages of the Spring Framework’s Transaction Support Model
1.1.1. Global Transactions
1.1.2. Local Transactions
1.1.3. Spring Framework’s Consistent Programming Model
1.2. Understanding the Spring Framework Transaction Abstraction
1.2.1. Hibernate Transaction Setup
1.3. Synchronizing Resources with Transactions
1.3.1. High-level Synchronization Approach
1.3.2. Low-level Synchronization Approach
1.3.3.  TransactionAwareDataSourceProxy
1.4. Declarative Transaction Management
1.4.1. Understanding the Spring Framework’s Declarative Transaction Implementation
1.4.2. Example of Declarative Transaction Implementation
1.4.3. Rolling Back a Declarative Transaction
1.4.4. Configuring Different Transactional Semantics for Different Beans
1.4.5. <tx:advice/> Settings
1.4.6. Using  @Transactional
@Transactional  Settings

Multiple Transaction Managers with  @Transactional


Custom Composed Annotations
1.4.7. Transaction Propagation
Understanding  PROPAGATION_REQUIRED
Understanding  PROPAGATION_REQUIRES_NEW
Understanding  PROPAGATION_NESTED
1.4.8. Advising Transactional Operations
1.4.9. Using  @Transactional  with AspectJ
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 1/155
7/31/22, 5:50 PM Data Access

1.5. Programmatic Transaction Management


1.5.1. Using the  TransactionTemplate
Specifying Transaction Settings
1.5.2. Using the  TransactionOperator
Cancel Signals
Specifying Transaction Settings
1.5.3. Using the  TransactionManager
Using the  PlatformTransactionManager
Using the  ReactiveTransactionManager
1.6. Choosing Between Programmatic and Declarative Transaction Management
1.7. Transaction-bound Events
1.8. Application server-specific integration
1.8.1. IBM WebSphere
1.8.2. Oracle WebLogic Server
1.9. Solutions to Common Problems
1.9.1. Using the Wrong Transaction Manager for a Specific  DataSource
1.10. Further Resources
2. DAO Support
2.1. Consistent Exception Hierarchy
2.2. Annotations Used to Configure DAO or Repository Classes
3. Data Access with JDBC
3.1. Choosing an Approach for JDBC Database Access
3.2. Package Hierarchy
3.3. Using the JDBC Core Classes to Control Basic JDBC Processing and Error Handling
3.3.1. Using  JdbcTemplate
Querying ( SELECT )
Updating ( INSERT ,  UPDATE , and  DELETE ) with  JdbcTemplate
Other  JdbcTemplate  Operations
JdbcTemplate  Best Practices

3.3.2. Using  NamedParameterJdbcTemplate


3.3.3. Using  SQLExceptionTranslator
3.3.4. Running Statements
3.3.5. Running Queries
3.3.6. Updating the Database

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 2/155
7/31/22, 5:50 PM Data Access

3.3.7. Retrieving Auto-generated Keys


3.4. Controlling Database Connections
3.4.1. Using  DataSource
3.4.2. Using  DataSourceUtils
3.4.3. Implementing  SmartDataSource
3.4.4. Extending  AbstractDataSource
3.4.5. Using  SingleConnectionDataSource
3.4.6. Using  DriverManagerDataSource
3.4.7. Using  TransactionAwareDataSourceProxy
3.4.8. Using  DataSourceTransactionManager
3.5. JDBC Batch Operations
3.5.1. Basic Batch Operations with  JdbcTemplate
3.5.2. Batch Operations with a List of Objects
3.5.3. Batch Operations with Multiple Batches
3.6. Simplifying JDBC Operations with the  SimpleJdbc  Classes
3.6.1. Inserting Data by Using  SimpleJdbcInsert
3.6.2. Retrieving Auto-generated Keys by Using  SimpleJdbcInsert
3.6.3. Specifying Columns for a  SimpleJdbcInsert
3.6.4. Using  SqlParameterSource  to Provide Parameter Values
3.6.5. Calling a Stored Procedure with  SimpleJdbcCall
3.6.6. Explicitly Declaring Parameters to Use for a  SimpleJdbcCall
3.6.7. How to Define  SqlParameters
3.6.8. Calling a Stored Function by Using  SimpleJdbcCall
3.6.9. Returning a  ResultSet  or REF Cursor from a  SimpleJdbcCall
3.7. Modeling JDBC Operations as Java Objects
3.7.1. Understanding  SqlQuery
3.7.2. Using  MappingSqlQuery
3.7.3. Using  SqlUpdate
3.7.4. Using  StoredProcedure
3.8. Common Problems with Parameter and Data Value Handling
3.8.1. Providing SQL Type Information for Parameters
3.8.2. Handling BLOB and CLOB objects
3.8.3. Passing in Lists of Values for IN Clause
3.8.4. Handling Complex Types for Stored Procedure Calls

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 3/155
7/31/22, 5:50 PM Data Access

3.9. Embedded Database Support


3.9.1. Why Use an Embedded Database?
3.9.2. Creating an Embedded Database by Using Spring XML
3.9.3. Creating an Embedded Database Programmatically
3.9.4. Selecting the Embedded Database Type
Using HSQL
Using H2
Using Derby
3.9.5. Testing Data Access Logic with an Embedded Database
3.9.6. Generating Unique Names for Embedded Databases
3.9.7. Extending the Embedded Database Support
3.10. Initializing a  DataSource
3.10.1. Initializing a Database by Using Spring XML
Initialization of Other Components that Depend on the Database
4. Data Access with R2DBC
4.1. Package Hierarchy
4.2. Using the R2DBC Core Classes to Control Basic R2DBC Processing and Error Handling
4.2.1. Using  DatabaseClient
Executing Statements
Querying ( SELECT )
Updating ( INSERT ,  UPDATE , and  DELETE ) with  DatabaseClient
Binding Values to Queries
Statement Filters
DatabaseClient  Best Practices

4.3. Retrieving Auto-generated Keys


4.4. Controlling Database Connections
4.4.1. Using  ConnectionFactory
4.4.2. Using  ConnectionFactoryUtils
4.4.3. Using  SingleConnectionFactory
4.4.4. Using  TransactionAwareConnectionFactoryProxy
4.4.5. Using  R2dbcTransactionManager
5. Object Relational Mapping (ORM) Data Access
5.1. Introduction to ORM with Spring
5.2. General ORM Integration Considerations

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 4/155
7/31/22, 5:50 PM Data Access

5.2.1. Resource and Transaction Management


5.2.2. Exception Translation
5.3. Hibernate
5.3.1.  SessionFactory  Setup in a Spring Container
5.3.2. Implementing DAOs Based on the Plain Hibernate API
5.3.3. Declarative Transaction Demarcation
5.3.4. Programmatic Transaction Demarcation
5.3.5. Transaction Management Strategies
5.3.6. Comparing Container-managed and Locally Defined Resources
5.3.7. Spurious Application Server Warnings with Hibernate
5.4. JPA
5.4.1. Three Options for JPA Setup in a Spring Environment
Using  LocalEntityManagerFactoryBean
Obtaining an EntityManagerFactory from JNDI
Using  LocalContainerEntityManagerFactoryBean
Dealing with Multiple Persistence Units
Background Bootstrapping
5.4.2. Implementing DAOs Based on JPA:  EntityManagerFactory  and  EntityManager
5.4.3. Spring-driven JPA transactions
5.4.4. Understanding  JpaDialect  and  JpaVendorAdapter
5.4.5. Setting up JPA with JTA Transaction Management
5.4.6. Native Hibernate Setup and Native Hibernate Transactions for JPA Interaction
6. Marshalling XML by Using Object-XML Mappers
6.1. Introduction
6.1.1. Ease of configuration
6.1.2. Consistent Interfaces
6.1.3. Consistent Exception Hierarchy
6.2.  Marshaller  and  Unmarshaller
6.2.1. Understanding  Marshaller
6.2.2. Understanding  Unmarshaller
6.2.3. Understanding  XmlMappingException
6.3. Using  Marshaller  and  Unmarshaller
6.4. XML Configuration Namespace
6.5. JAXB

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 5/155
7/31/22, 5:50 PM Data Access

6.5.1. Using  Jaxb2Marshaller


XML Configuration Namespace
6.6. JiBX
6.6.1. Using  JibxMarshaller
XML Configuration Namespace
6.7. XStream
6.7.1. Using  XStreamMarshaller
7. Appendix
7.1. XML Schemas
7.1.1. The  tx  Schema
7.1.2. The  jdbc  Schema

This part of the reference documentation is concerned with data access and the interaction
between the data access layer and the business or service layer.

Spring’s comprehensive transaction management support is covered in some detail, followed by


thorough coverage of the various data access frameworks and technologies with which the Spring
Framework integrates.

1. Transaction Management
Comprehensive transaction support is among the most compelling reasons to use the Spring
Framework. The Spring Framework provides a consistent abstraction for transaction management
that delivers the following benefits:

A consistent programming model across different transaction APIs, such as Java Transaction
API (JTA), JDBC, Hibernate, and the Java Persistence API (JPA).

Support for declarative transaction management.

A simpler API for programmatic transaction management than complex transaction APIs, such


as JTA.

Excellent integration with Spring’s data access abstractions.

The following sections describe the Spring Framework’s transaction features and technologies:

Advantages of the Spring Framework’s transaction support model describes why you would
use the Spring Framework’s transaction abstraction instead of EJB Container-Managed

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 6/155
7/31/22, 5:50 PM Data Access

Transactions (CMT) or choosing to drive local transactions through a proprietary API, such as
Hibernate.

Understanding the Spring Framework transaction abstraction outlines the core classes and
describes how to configure and obtain  DataSource  instances from a variety of sources.

Synchronizing resources with transactions describes how the application code ensures that
resources are created, reused, and cleaned up properly.

Declarative transaction management describes support for declarative transaction


management.

Programmatic transaction management covers support for programmatic (that is, explicitly


coded) transaction management.

Transaction bound event describes how you could use application events within a transaction.

The chapter also includes discussions of best practices, application server integration,


and solutions to common problems.

1.1. Advantages of the Spring Framework’s Transaction


Support Model
Traditionally, Java EE developers have had two choices for transaction management: global or
local transactions, both of which have profound limitations. Global and local transaction
management is reviewed in the next two sections, followed by a discussion of how the Spring
Framework’s transaction management support addresses the limitations of the global and local
transaction models.

1.1.1. Global Transactions


Global transactions let you work with multiple transactional resources, typically relational
databases and message queues. The application server manages global transactions through the
JTA, which is a cumbersome API (partly due to its exception model). Furthermore, a
JTA  UserTransaction  normally needs to be sourced from JNDI, meaning that you also need to
use JNDI in order to use JTA. The use of global transactions limits any potential reuse of
application code, as JTA is normally only available in an application server environment.

Previously, the preferred way to use global transactions was through EJB CMT (Container
Managed Transaction). CMT is a form of declarative transaction management (as distinguished
from programmatic transaction management). EJB CMT removes the need for transaction-related
JNDI lookups, although the use of EJB itself necessitates the use of JNDI. It removes most but not
all of the need to write Java code to control transactions. The significant downside is that CMT is
tied to JTA and an application server environment. Also, it is only available if one chooses to

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 7/155
7/31/22, 5:50 PM Data Access

implement business logic in EJBs (or at least behind a transactional EJB facade). The negatives of
EJB in general are so great that this is not an attractive proposition, especially in the face of
compelling alternatives for declarative transaction management.

1.1.2. Local Transactions


Local transactions are resource-specific, such as a transaction associated with a JDBC
connection. Local transactions may be easier to use but have a significant disadvantage: They
cannot work across multiple transactional resources. For example, code that manages
transactions by using a JDBC connection cannot run within a global JTA transaction. Because the
application server is not involved in transaction management, it cannot help ensure correctness
across multiple resources. (It is worth noting that most applications use a single transaction
resource.) Another downside is that local transactions are invasive to the programming model.

1.1.3. Spring Framework’s Consistent Programming Model


Spring resolves the disadvantages of global and local transactions. It lets application developers
use a consistent programming model in any environment. You write your code once, and it can
benefit from different transaction management strategies in different environments. The Spring
Framework provides both declarative and programmatic transaction management. Most users
prefer declarative transaction management, which we recommend in most cases.

With programmatic transaction management, developers work with the Spring Framework
transaction abstraction, which can run over any underlying transaction infrastructure. With the
preferred declarative model, developers typically write little or no code related to transaction
management and, hence, do not depend on the Spring Framework transaction API or any other
transaction API.

Do you need an application server for transaction management?


The Spring Framework’s transaction management support changes traditional rules as to
when an enterprise Java application requires an application server.

In particular, you do not need an application server purely for declarative transactions
through EJBs. In fact, even if your application server has powerful JTA capabilities, you may
decide that the Spring Framework’s declarative transactions offer more power and a more
productive programming model than EJB CMT.

Typically, you need an application server’s JTA capability only if your application needs to
handle transactions across multiple resources, which is not a requirement for many
applications. Many high-end applications use a single, highly scalable database (such as
Oracle RAC) instead. Stand-alone transaction managers (such as Atomikos
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 8/155
7/31/22, 5:50 PM Data Access

Transactions and JOTM) are other options. Of course, you may need other application
server capabilities, such as Java Message Service (JMS) and Java EE Connector
Architecture (JCA).

The Spring Framework gives you the choice of when to scale your application to a fully
loaded application server. Gone are the days when the only alternative to using EJB CMT or
JTA was to write code with local transactions (such as those on JDBC connections) and face
a hefty rework if you need that code to run within global, container-managed transactions.
With the Spring Framework, only some of the bean definitions in your configuration file need
to change (rather than your code).

1.2. Understanding the Spring Framework Transaction


Abstraction
The key to the Spring transaction abstraction is the notion of a transaction strategy. A transaction
strategy is defined by a  TransactionManager , specifically
the  org.springframework.transaction.PlatformTransactionManager  interface for imperative
transaction management and
the  org.springframework.transaction.ReactiveTransactionManager  interface for reactive
transaction management. The following listing shows the definition of
the  PlatformTransactionManager  API:

public interface PlatformTransactionManager extends TransactionManager {

TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionExcep

void commit(TransactionStatus status) throws TransactionException;

void rollback(TransactionStatus status) throws TransactionException;

This is primarily a service provider interface (SPI), although you can use it programmatically from
your application code. Because  PlatformTransactionManager  is an interface, it can be easily
mocked or stubbed as necessary. It is not tied to a lookup strategy, such as
JNDI.  PlatformTransactionManager  implementations are defined like any other object (or bean) 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 much more
easily than if it used JTA directly.

Again, in keeping with Spring’s philosophy, the  TransactionException  that can be thrown by any
of the  PlatformTransactionManager  interface’s methods is unchecked (that is, it extends
the  java.lang.RuntimeException  class). Transaction infrastructure failures are almost invariably
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 9/155
7/31/22, 5:50 PM Data Access

fatal. In rare cases where application code can actually recover from a transaction failure, the
application developer can still choose to catch and handle  TransactionException . The salient
point is that developers are not forced to do so.

The  getTransaction(..)  method returns a  TransactionStatus  object, depending on


a  TransactionDefinition  parameter. The returned  TransactionStatus  might represent a new
transaction or can represent an existing transaction, if a matching transaction exists in the current
call stack. The implication in this latter case is that, as with Java EE transaction contexts,
a  TransactionStatus  is associated with a thread of execution.

As of Spring Framework 5.2, Spring also provides a transaction management abstraction for
reactive applications that make use of reactive types or Kotlin Coroutines. The following listing
shows the transaction strategy defined
by  org.springframework.transaction.ReactiveTransactionManager :

public interface ReactiveTransactionManager extends TransactionManager {

Mono<ReactiveTransaction> getReactiveTransaction(TransactionDefinition definition) throws

Mono<Void> commit(ReactiveTransaction status) throws TransactionException;

Mono<Void> rollback(ReactiveTransaction status) throws TransactionException;

The reactive transaction manager is primarily a service provider interface (SPI), although you can
use it programmatically from your application code. Because  ReactiveTransactionManager  is an
interface, it can be easily mocked or stubbed as necessary.

The  TransactionDefinition  interface specifies:

Propagation: Typically, all code within a transaction scope runs in that transaction. However,
you can specify the behavior if a transactional method is run when a transaction context
already exists. For example, code can continue running in the existing transaction (the
common case), or the existing transaction can be suspended and a new transaction created.
Spring offers all of the transaction propagation options familiar from EJB CMT. To read about
the semantics of transaction propagation in Spring, see Transaction Propagation.

Isolation: The degree to which this transaction is isolated from the work of other transactions.
For example, can this transaction see uncommitted writes from other transactions?

Timeout: How long this transaction runs before timing out and being automatically rolled back
by the underlying transaction infrastructure.

Read-only status: You can use a read-only transaction when your code reads but does not
modify data. Read-only transactions can be a useful optimization in some cases, such as when

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 10/155
7/31/22, 5:50 PM Data Access

you use Hibernate.

These settings reflect standard transactional concepts. If necessary, refer to resources that
discuss transaction isolation levels and other core transaction concepts. Understanding these
concepts is essential to using the Spring Framework or any transaction management solution.

The  TransactionStatus  interface provides a simple way for transactional code to control
transaction execution and query transaction status. The concepts should be familiar, as they are
common to all transaction APIs. The following listing shows the  TransactionStatus  interface:

public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {

@Override

boolean isNewTransaction();

boolean hasSavepoint();

@Override

void setRollbackOnly();

@Override

boolean isRollbackOnly();

void flush();

@Override

boolean isCompleted();

Regardless of whether you opt for declarative or programmatic transaction management in Spring,
defining the correct  TransactionManager  implementation is absolutely essential. You typically
define this implementation through dependency injection.

TransactionManager  implementations normally require knowledge of the environment in which


they work: JDBC, JTA, Hibernate, and so on. The following examples show how you can define a
local  PlatformTransactionManager  implementation (in this case, with plain JDBC.)

You can define a JDBC  DataSource  by creating a bean similar to the following:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="${jdbc.driverClassName}" />

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

</bean>

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 11/155
7/31/22, 5:50 PM Data Access

The related  PlatformTransactionManager  bean definition then has a reference to


the  DataSource  definition. It should resemble the following example:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">


<property name="dataSource" ref="dataSource"/>

</bean>

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 and JNDI lookup version would look like:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:jee="http://www.springframework.org/schema/jee"

xsi:schemaLocation="

http://www.springframework.org/schema/beans

https://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/jee

https://www.springframework.org/schema/jee/spring-jee.xsd">

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

<!-- other <bean/> definitions here -->

</beans>

The  JtaTransactionManager  does not need to know about the  DataSource  (or any other specific
resources) because it uses the container’s global transaction management infrastructure.

The preceding definition of the  dataSource  bean uses the  <jndi-lookup/>  tag from
the  jee  namespace. For more information see The JEE Schema.

If you use JTA, your transaction manager definition should look the same, regardless of what
data access technology you use, be it JDBC, Hibernate JPA, or any other supported
technology. This is due to the fact that JTA transactions are global transactions, which can
enlist any transactional resource.

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 12/155
7/31/22, 5:50 PM Data Access

In all Spring transaction setups, application code does not need to change. You can change how
transactions are managed merely by changing configuration, even if that change means moving
from local to global transactions or vice versa.

1.2.1. Hibernate Transaction Setup


You can also easily use Hibernate local transactions, as shown in the following examples. In this
case, you need to define a Hibernate  LocalSessionFactoryBean , which your application code can
use to obtain Hibernate  Session  instances.

The  DataSource  bean definition is similar to the local JDBC example shown previously and, thus,
is not shown in the following example.

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 Spring
Framework (rather than the Java EE container) manages the transactions.

The  txManager  bean in this case is of the  HibernateTransactionManager  type. In the same way as
the  DataSourceTransactionManager  needs a reference to the  DataSource ,
the  HibernateTransactionManager  needs a reference to the  SessionFactory . The following
example declares  sessionFactory  and  txManager  beans:

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

<property name="dataSource" ref="dataSource"/>

<property name="mappingResources">

<list>

<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>

</list>

</property>

<property name="hibernateProperties">

<value>

hibernate.dialect=${hibernate.dialect}

</value>

</property>

</bean>

<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory"/>

</bean>

If you use Hibernate and Java EE container-managed JTA transactions, you should use the
same  JtaTransactionManager  as in the previous JTA example for JDBC, as the following example

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 13/155
7/31/22, 5:50 PM Data Access

shows. Also, it is recommended to make Hibernate aware of JTA through its transaction
coordinator and possibly also its connection release mode configuration:

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

<property name="dataSource" ref="dataSource"/>

<property name="mappingResources">

<list>

<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>

</list>

</property>

<property name="hibernateProperties">

<value>

hibernate.dialect=${hibernate.dialect}

hibernate.transaction.coordinator_class=jta

hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
</value>

</property>

</bean>

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

Or alternatively, you may pass the  JtaTransactionManager  into your  LocalSessionFactoryBean  for
enforcing the same defaults:

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

<property name="dataSource" ref="dataSource"/>

<property name="mappingResources">

<list>

<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>

</list>

</property>

<property name="hibernateProperties">

<value>

hibernate.dialect=${hibernate.dialect}

</value>

</property>

<property name="jtaTransactionManager" ref="txManager"/>

</bean>

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

1.3. Synchronizing Resources with Transactions


How to create different transaction managers and how they are linked to related resources that
need to be synchronized to transactions (for example  DataSourceTransactionManager  to a
JDBC  DataSource ,  HibernateTransactionManager  to a Hibernate  SessionFactory , and so forth)
should now be clear. This section describes how the application code (directly or indirectly, by
using a persistence API such as JDBC, Hibernate, or JPA) ensures that these resources are
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 14/155
7/31/22, 5:50 PM Data Access

created, reused, and cleaned up properly. The section also discusses how transaction
synchronization is (optionally) triggered through the relevant  TransactionManager .

1.3.1. High-level Synchronization Approach


The preferred approach is to use Spring’s highest-level template-based persistence integration
APIs or to use native ORM APIs with transaction-aware factory beans or proxies for managing the
native resource factories. These transaction-aware solutions internally handle resource creation
and reuse, cleanup, optional transaction synchronization of the resources, and exception
mapping. Thus, user data access code does 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 for JDBC access by using the  JdbcTemplate . These solutions are detailed in
subsequent sections of this reference documentation.

1.3.2. Low-level Synchronization Approach


Classes such as  DataSourceUtils  (for JDBC),  EntityManagerFactoryUtils  (for
JPA),  SessionFactoryUtils  (for Hibernate), and so on exist at a lower level. When you want the
application code to deal directly with the resource types of the native persistence APIs, you use
these classes to ensure that proper Spring Framework-managed instances are obtained,
transactions are (optionally) synchronized, and exceptions that occur in the process are properly
mapped to a consistent API.

For example, in the case of JDBC, instead of the traditional JDBC approach of calling
the  getConnection()  method on the  DataSource , you can instead use
Spring’s  org.springframework.jdbc.datasource.DataSourceUtils  class, as follows:

Connection conn = DataSourceUtils.getConnection(dataSource);

If an existing transaction already has a connection synchronized (linked) to it, that instance is
returned. Otherwise, the method call triggers the creation of a new connection, which is
(optionally) synchronized to any existing transaction and made available for subsequent reuse in
that same transaction. As mentioned earlier, any  SQLException  is wrapped in a Spring
Framework  CannotGetJdbcConnectionException , one of the Spring Framework’s hierarchy of
unchecked  DataAccessException  types. This approach gives you more information than can be
obtained easily from the  SQLException  and ensures portability across databases and even across
different persistence technologies.

This approach also works without Spring transaction management (transaction synchronization is
optional), so you can use it whether or not you use Spring for transaction management.

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 15/155
7/31/22, 5:50 PM Data Access

Of course, once you have used Spring’s JDBC support, JPA support, or Hibernate support, you
generally prefer not to use  DataSourceUtils  or the other helper classes, because you are much
happier working through the Spring abstraction than directly with the relevant APIs. For example, if
you use the Spring  JdbcTemplate  or  jdbc.object  package to simplify your use of JDBC, correct
connection retrieval occurs behind the scenes and you need not write any special code.

1.3.3.  TransactionAwareDataSourceProxy
At the very lowest level exists the  TransactionAwareDataSourceProxy  class. This is a proxy for a
target  DataSource , which wraps the target  DataSource  to add awareness of Spring-managed
transactions. In this respect, it is similar to a transactional JNDI  DataSource , as provided by a
Java EE server.

You should almost never need or want to use this class, except when existing code must be called
and passed a standard JDBC  DataSource  interface implementation. In that case, it is possible that
this code is usable but is participating in Spring-managed transactions. You can write your new
code by using the higher-level abstractions mentioned earlier.

1.4. Declarative Transaction Management

Most Spring Framework users choose declarative transaction management. This option has
the least impact on application code and, hence, is most consistent with the ideals of a non-
invasive lightweight container.

The Spring Framework’s declarative transaction management is made possible with Spring
aspect-oriented programming (AOP). However, as the transactional aspects code comes with the
Spring Framework distribution and may be used in a boilerplate fashion, AOP concepts do not
generally have to be understood to make effective use of this code.

The Spring Framework’s declarative transaction management is similar to EJB CMT, in that you
can specify transaction behavior (or lack of it) down to the individual method level. You can make
a  setRollbackOnly()  call within a transaction context, if necessary. The differences between the
two types of transaction management are:

Unlike EJB CMT, which is tied to JTA, the Spring Framework’s declarative transaction
management works in any environment. It can work with JTA transactions or local transactions
by using JDBC, JPA, or Hibernate by adjusting the configuration files.

You can apply the Spring Framework declarative transaction management to any class, not
merely special classes such as EJBs.
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 16/155
7/31/22, 5:50 PM Data Access

The Spring Framework offers declarative rollback rules, a feature with no EJB equivalent. Both
programmatic and declarative support for rollback rules is provided.

The Spring Framework lets you customize transactional behavior by using AOP. For example,
you can insert custom behavior in the case of transaction rollback. You can also add arbitrary
advice, along with transactional advice. With EJB CMT, you cannot influence the container’s
transaction management, except with  setRollbackOnly() .

The Spring Framework does not support propagation of transaction contexts across remote
calls, as high-end application servers do. If you need this feature, we recommend that you use
EJB. However, consider carefully before using such a feature, because, normally, one does not
want transactions to span remote calls.

The concept of rollback rules is important. They let you specify which exceptions (and throwables)
should cause automatic rollback. You can specify this declaratively, in configuration, not in Java
code. So, although you can still call  setRollbackOnly()  on the  TransactionStatus  object to roll
back the current transaction back, most often you can specify a rule
that  MyApplicationException  must always result in rollback. The significant advantage to this
option is that business objects do not depend on the transaction infrastructure. For example, they
typically do not need to import Spring transaction APIs or other Spring APIs.

Although EJB container default behavior automatically rolls back the transaction on a system
exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically
on an application exception (that is, a checked exception other than  java.rmi.RemoteException ).
While the Spring default behavior for declarative transaction management follows EJB convention
(roll back is automatic only on unchecked exceptions), it is often useful to customize this behavior.

1.4.1. Understanding the Spring Framework’s Declarative


Transaction Implementation
It is not sufficient merely to tell you to annotate your classes with the  @Transactional  annotation,
add  @EnableTransactionManagement  to your configuration, and expect you to understand how it all
works. To provide a deeper understanding, this section explains the inner workings of the Spring
Framework’s declarative transaction infrastructure in the context of transaction-related issues.

The most important concepts to grasp with regard to the Spring Framework’s declarative
transaction support are that this support is enabled via AOP proxies and that the transactional
advice is driven by metadata (currently XML- or annotation-based). The combination of AOP with
transactional metadata yields an AOP proxy that uses a  TransactionInterceptor  in conjunction
with an appropriate  TransactionManager  implementation to drive transactions around method
invocations.

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 17/155
7/31/22, 5:50 PM Data Access

Spring AOP is covered in the AOP section.

Spring Framework’s  TransactionInterceptor  provides transaction management for imperative


and reactive programming models. The interceptor detects the desired flavor of transaction
management by inspecting the method return type. Methods returning a reactive type such
as  Publisher  or Kotlin  Flow  (or a subtype of those) qualify for reactive transaction management.
All other return types including  void  use the code path for imperative transaction management.

Transaction management flavors impact which transaction manager is required. Imperative


transactions require a  PlatformTransactionManager , while reactive transactions
use  ReactiveTransactionManager  implementations.

@Transactional  commonly works with thread-bound transactions managed


by  PlatformTransactionManager , exposing a transaction to all data access operations within
the current execution thread. Note: This does not propagate to newly started threads within
the method.

A reactive transaction managed by  ReactiveTransactionManager  uses the Reactor context


instead of thread-local attributes. As a consequence, all participating data access operations
need to execute within the same Reactor context in the same reactive pipeline.

The following image shows a conceptual view of calling a method on a transactional proxy:

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 18/155
7/31/22, 5:50 PM Data Access

1.4.2. Example of Declarative Transaction Implementation


Consider the following interface and its attendant implementation. This example
uses  Foo  and  Bar  classes as placeholders so that you can concentrate on the transaction usage
without focusing on a particular domain model. For the purposes of this example, the fact that
the  DefaultFooService  class throws  UnsupportedOperationException  instances in the body of
each implemented method is good. That behavior lets you see transactions being created and
then rolled back in response to the  UnsupportedOperationException  instance. The following listing
shows the  FooService  interface:

Java Kotlin

// the service interface that we want to make transactional

package x.y.service;

public interface FooService {

Foo getFoo(String fooName);

Foo getFoo(String fooName, String barName);

void insertFoo(Foo foo);

void updateFoo(Foo foo);

The following example shows an implementation of the preceding interface:

Java Kotlin

package x.y.service;

public class DefaultFooService implements FooService {

@Override

public Foo getFoo(String fooName) {

// ...

@Override

public Foo getFoo(String fooName, String barName) {

// ...

@Override

public void insertFoo(Foo foo) {

// ...

@Override

public void updateFoo(Foo foo) {

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 19/155
7/31/22, 5:50 PM Data Access

// ...

Assume that the first two methods of


the  FooService  interface,  getFoo(String)  and  getFoo(String, String) , must run in the context
of a transaction with read-only semantics and that the other
methods,  insertFoo(Foo)  and  updateFoo(Foo) , must run in the context of a transaction with read-
write semantics. The following configuration is explained in detail in the next few paragraphs:

<!-- from the file 'context.xml' -->

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="

http://www.springframework.org/schema/beans

https://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/tx

https://www.springframework.org/schema/tx/spring-tx.xsd

http://www.springframework.org/schema/aop

https://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- this is the service object that we want to make transactional -->

<bean id="fooService" class="x.y.service.DefaultFooService"/>

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->

<tx:advice id="txAdvice" transaction-manager="txManager">

<!-- the transactional semantics... -->

<tx:attributes>

<!-- all methods starting with 'get' are read-only -->

<tx:method name="get*" read-only="true"/>

<!-- other methods use the default transaction settings (see below) -->

<tx:method name="*"/>

</tx:attributes>

</tx:advice>

<!-- ensure that the above transactional advice runs for any execution

of an operation defined by the FooService interface -->

<aop:config>

<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.


<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>

</aop:config>

<!-- don't forget the DataSource -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="clos


<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>

<property name="username" value="scott"/>

<property name="password" value="tiger"/>

</bean>

<!-- similarly, don't forget the TransactionManager -->

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManag


https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 20/155
7/31/22, 5:50 PM Data Access

<property name="dataSource" ref="dataSource"/>

</bean>

<!-- other <bean/> definitions here -->

</beans>

Examine the preceding configuration. It assumes that you want to make a service object,
the  fooService  bean, transactional. The transaction semantics to apply are encapsulated in
the  <tx:advice/>  definition. The  <tx:advice/>  definition reads as "all methods starting
with  get  are to run in the context of a read-only transaction, and all other methods are to run with
the default transaction semantics". 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
case, the  txManager  bean).

You can omit the  transaction-manager  attribute in the transactional advice ( <tx:advice/> ) 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 wire in has any
other name, you must use the  transaction-manager  attribute explicitly, as in the preceding
example.

The  <aop:config/>  definition ensures that the transactional advice defined by the  txAdvice  bean
runs at the appropriate points in the program. First, you define a pointcut that matches the
execution of any operation defined in the  FooService  interface ( fooServiceOperation ). Then you
associate the pointcut with the  txAdvice  by using an advisor. The result indicates that, at the
execution of a  fooServiceOperation , the advice defined by  txAdvice  is run.

The expression defined within the  <aop:pointcut/>  element is an AspectJ pointcut expression.
See the AOP section for more details on pointcut expressions in Spring.

A common requirement is to make an entire service layer transactional. The best way to do this is
to change the pointcut expression to match any operation in your service layer. The following
example shows how to do so:

<aop:config>

<aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>

<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>

</aop:config>

In the preceding example, it is assumed that all your service interfaces are defined in
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 21/155
7/31/22, 5:50 PM Data Access

the  x.y.service  package. See the AOP section for more details.

Now that we have analyzed the configuration, you may be asking yourself, "What does all this
configuration actually do?"

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 the transactional advice
so that, when an appropriate method is invoked on the proxy, a transaction is started, suspended,
marked as read-only, and so on, depending on the transaction configuration associated with that
method. Consider the following program that test drives the configuration shown earlier:

Java Kotlin

public final class Boot {

public static void main(final String[] args) throws Exception {

ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml");

FooService fooService = ctx.getBean(FooService.class);

fooService.insertFoo(new Foo());

The output from running the preceding program should resemble the following (the Log4J output
and the stack trace from the  UnsupportedOperationException  thrown by
the  insertFoo(..)  method of the  DefaultFooService  class have been truncated for clarity):

<!-- the Spring container is starting up... -->

[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy for bean '

<!-- the DefaultFooService is actually proxied -->

[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]

<!-- ... the insertFoo(..) method is now being invoked on the proxy -->

[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo

<!-- the transactional advice kicks in here... -->

[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.in


[DataSourceTransactionManager] - Acquired Connection [org.apache.commons.dbcp.PoolableConnecti

<!-- the insertFoo(..) method from DefaultFooService throws an exception... -->

[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should rollb


[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertF

<!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [org.apache.commo
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction

[DataSourceUtils] - Returning JDBC Connection to DataSource

Exception in thread "main" java.lang.UnsupportedOperationException at x.y.service.DefaultFooSe


<!-- AOP infrastructure stack trace elements removed for clarity -->

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 22/155
7/31/22, 5:50 PM Data Access

at $Proxy0.insertFoo(Unknown Source)

at Boot.main(Boot.java:11)

To use reactive transaction management the code has to use reactive types.

Spring Framework uses the  ReactiveAdapterRegistry  to determine whether a method return
type is reactive.

The following listing shows a modified version of the previously used  FooService , but this time the
code uses reactive types:

Java Kotlin

// the reactive service interface that we want to make transactional

package x.y.service;

public interface FooService {

Flux<Foo> getFoo(String fooName);

Publisher<Foo> getFoo(String fooName, String barName);

Mono<Void> insertFoo(Foo foo);

Mono<Void> updateFoo(Foo foo);

The following example shows an implementation of the preceding interface:

Java Kotlin

package x.y.service;

public class DefaultFooService implements FooService {

@Override

public Flux<Foo> getFoo(String fooName) {

// ...

@Override

public Publisher<Foo> getFoo(String fooName, String barName) {

// ...

@Override

public Mono<Void> insertFoo(Foo foo) {

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 23/155
7/31/22, 5:50 PM Data Access

// ...

@Override

public Mono<Void> updateFoo(Foo foo) {

// ...

Imperative and reactive transaction management share the same semantics for transaction
boundary and transaction attribute definitions. The main difference between imperative and
reactive transactions is the deferred nature of the latter.  TransactionInterceptor  decorates the
returned reactive type with a transactional operator to begin and clean up the transaction.
Therefore, calling a transactional reactive method defers the actual transaction management to a
subscription type that activates processing of the reactive type.

Another aspect of reactive transaction management relates to data escaping which is a natural
consequence of the programming model.

Method return values of imperative transactions are returned from transactional methods upon
successful termination of a method so that partially computed results do not escape the method
closure.

Reactive transaction methods return a reactive wrapper type which represents a computation
sequence along with a promise to begin and complete the computation.

A  Publisher  can emit data while a transaction is ongoing but not necessarily completed.
Therefore, methods that depend upon successful completion of an entire transaction need to
ensure completion and buffer results in the calling code.

1.4.3. Rolling Back a Declarative Transaction


The previous section outlined the basics of how to specify transactional settings for classes,
typically service layer classes, declaratively in your application. This section describes how you
can control the rollback of transactions in a simple, declarative fashion in XML configuration. For
details on controlling rollback semantics declaratively with the  @Transactional  annotation,
see  @Transactional  Settings.

The recommended way to indicate to the Spring Framework’s transaction infrastructure that a
transaction’s work is to be rolled back is to throw an  Exception  from code that is currently
executing in the context of a transaction. The Spring Framework’s transaction infrastructure code
catches any unhandled  Exception  as it bubbles up the call stack and makes a determination
whether to mark the transaction for rollback.

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 24/155
7/31/22, 5:50 PM Data Access

In its default configuration, the Spring Framework’s transaction infrastructure code marks a
transaction for rollback only in the case of runtime, unchecked exceptions. That is, when the
thrown exception is an instance or subclass of  RuntimeException . ( Error  instances also, by
default, result in a rollback). Checked exceptions that are thrown from a transactional method do
not result in rollback in the default configuration.

You can configure exactly which  Exception  types mark a transaction for rollback, including
checked exceptions by specifying rollback rules.

Rollback rules

Rollback rules determine if a transaction should be rolled back when a given exception is
thrown, and the rules are based on patterns. A pattern can be a fully qualified class name or
a substring of a fully qualified class name for an exception type (which must be a subclass
of  Throwable ), with no wildcard support at present. For example, a value
of  "javax.servlet.ServletException"  or  "ServletException"  will
match  javax.servlet.ServletException  and its subclasses.

Rollback rules may be configured in XML via the  rollback-for  and  no-rollback-
for  attributes, which allow patterns to be specified as strings. When using  @Transactional ,
rollback rules may be configured via
the  rollbackFor / noRollbackFor  and  rollbackForClassName / noRollbackForClassName  attributes,
which allow patterns to be specified as  Class  references or strings, respectively. When an
exception type is specified as a class reference its fully qualified name will be used as the
pattern. Consequently,  @Transactional(rollbackFor = example.CustomException.class)  is
equivalent to  @Transactional(rollbackForClassName = "example.CustomException") .

You must carefully consider how specific the pattern is and whether to include package
information (which isn’t mandatory). For example,  "Exception"  will match nearly
anything and will probably hide other rules.  "java.lang.Exception"  would be correct
if  "Exception"  were meant to define a rule for all checked exceptions. With more
unique exception names such as  "BaseBusinessException"  there is likely no need to
use the fully qualified class name for the exception pattern.

Furthermore, rollback rules may result in unintentional matches for similarly named
exceptions and nested classes. This is due to the fact that a thrown exception is
considered to be a match for a given rollback rule if the name of thrown exception
contains the exception pattern configured for the rollback rule. For example, given a
rule configured to match on  com.example.CustomException , that rule would match
against an exception named  com.example.CustomExceptionV2  (an exception in the
same package as  CustomException  but with an additional suffix) or an exception
https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#spring-data-tier 25/155

You might also like