How to create various transaction managers and how they are associated with the corresponding resources that need to
be synchronized with transactions (for example, DataSourceTransactionManager
with
DataSource
from JDBC, HibernateTransactionManager
with SessionFactory
from
Hibernate and so on) should be clear now. This section describes how application code (either directly or indirectly
through a persistence API such as JDBC, Hibernate, or JPA) ensures that these resources are created, reused, and
cleaned up properly. The section also discusses how transaction synchronization (optional) can be triggered through
the appropriate TransactionManager
.
High-level synchronization approach
The preferred approach is to use high-level template-based persistence integration APIs from Spring or use native ORM
APIs with transaction-oriented factory beans or proxies to manage native resource factories. These
transaction-oriented solutions internally handle resource creation and reuse, cleanup, optional resource
synchronization with transactions, and exception conversion. This way, custom data access code does not need to
handle these tasks, but can instead be refocused solely on non-stereotypical data persistence logic. Typically, you
use the built-in ORM API or use a template-based approach to achieve JDBC access using JdbcTemplate
.
These software solutions are described in detail in subsequent sections of this reference documentation.
Low-level synchronization approach
Classes like DataSourceUtils
(for JDBC), EntityManagerFactoryUtils
(for JPA), SessionFactoryUtils
(for Hibernate) and so on exist at a lower level. If you need your application code to work directly with the
resource types of the native persistence APIs, then use these classes to ensure that proper Spring Framework-managed
instances are retrieved, transactions are synchronized (optional), and exceptions thrown in the process are
correctly displayed in a consistent API. interface.
For example, in the case of JDBC, instead of the traditional JDBC approach of calling the
getConnection()
method on the DataSource
, you can use the org.springframework.jdbc.datasource.DataSourceUtils
class from Spring as shown below:
Connection conn = DataSourceUtils.getConnection(dataSource);
If an existing transaction already has a connection synchronized (bound) to it, this instance is returned. Otherwise,
calling the method results in the creation of a new connection, which is (optionally) synchronized with any existing
transaction and made available for later reuse in the same transaction. As mentioned earlier, any
SQLException
exception is wrapped in a CannotGetJdbcConnectionException
exception from
Spring Framewor, which is one of the exceptions in the DataAccessException
hierarchy of unchecked types
in the Spring Framework. This approach provides more information that can be easily obtained from
SQLException
, and provides portability between databases and even between different persistent storage
technologies.
This approach also works without Spring transaction management (transaction synchronization is optional), so you can use it whether you use Spring for transaction management or not.
Naturally, after using Spring's JDBC, JPA, or Hibernate support, it is usually preferable not to use DataSourceUtils
or other helper classes, since you will be much happier working through the Spring abstraction than working directly
with the associated APIs. interfaces. For example, if you use Spring's JdbcTemplate
or the jdbc.object
package to make JDBC easier to use, correct connection discovery happens behind the scenes without you having to
write any special code.
TransactionAwareDataSourceProxy
At the lowest level there is the TransactionAwareDataSourceProxy
class. This is a proxy for the target
DataSource
that wraps the target DataSource
to improve the compatibility level of
Spring-managed transactions. In this respect, it is similar to the JNDI transactional DataSource
provided by the Java EE server.
You will almost never need or want to use this class, except when you need to call existing code and pass it a
standard implementation of the DataSource
interface from JDBC. In this case, it is possible that this
code can be used, but it is involved in Spring-managed transactions. You can write new custom code using the
higher-level abstractions mentioned earlier.
GO TO FULL VERSION