It should now be clear how different transaction managers are
created, and how they are linked to related resources which need to be
synchronized to transactions (for example
to a JDBC
HibernateTransactionManager to a Hibernate
SessionFactory, and so forth). There remains the question
however of how the application code, directly or indirectly using a
persistence API (such as JDBC, Hibernate, and JDO), ensures that these resources
are obtained and handled properly in terms of proper
creation/reuse/cleanup and trigger (optionally) transaction
synchronization via the relevant
The preferred approach is to use Spring's highest level
persistence integration APIs. These do not replace the native APIs, but
internally handle resource creation/reuse, cleanup, optional
transaction synchronization of the resources and exception mapping so
that user data access code doesn't have to worry about these concerns at
all, but can concentrate purely on non-boilerplate persistence logic.
Generally, the same template approach is used
for all persistence APIs, with examples including the
JdoTemplate classes (detailed in subsequent chapters
of this reference documentation.
At a lower level exist classes such as
DataSourceUtils (for JDBC),
SessionFactoryUtils (for Hibernate),
PersistenceManagerFactoryUtils (for JDO), and so on.
When it is preferable for application code to deal directly with the
resource types of the native persistence APIs, these classes ensure that
proper Spring Framework-managed instances are obtained, transactions are
(optionally) synchronized, and exceptions which happen in the process
are properly mapped to a consistent API.
For example, in the case of JDBC, instead of the traditional JDBC approach of
getConnection() method on the
DataSource, you would instead use Spring's
class as follows:
Connection conn = DataSourceUtils.getConnection(dataSource);
If an existing transaction exists, and already has a connection
synchronized (linked) to it, that instance will be returned. Otherwise,
the method call will trigger the creation of a new connection, which
will be (optionally) synchronized to any existing transaction, and
made available for subsequent reuse in that same transaction. As mentioned,
this has the added advantage that any
will be wrapped in a Spring Framework
CannotGetJdbcConnectionException - one of the Spring
Framework's hierarchy of unchecked DataAccessExceptions. This gives you more
information than can easily be obtained from the
SQLException, and ensures portability across
databases: even across different persistence technologies.
It should be noted that this will also work fine without Spring transaction management (transaction synchronization is optional), so you can use it whether or not you are using Spring for transaction management.
Of course, once you've used Spring's JDBC support or Hibernate
support, you will generally prefer not to use
DataSourceUtils or the other helper classes, because
you'll be much happier working via the Spring abstraction than directly
with the relevant APIs. For example, if you use the Spring
package to simplify your use of JDBC, correct connection retrieval happens
behind the scenes and you won't need to write any special code.
At the very lowest level exists the
TransactionAwareDataSourceProxy class. This is a
proxy for a target
DataSource, which wraps the
DataSource to add awareness of Spring-managed
transactions. In this respect, it is similar to a transactional JNDI
DataSource as provided by a J2EE server.
It should almost never be necessary or desirable to use this
class, except when existing code exists which must be called and passed
a standard JDBC
DataSource interface implementation.
In that case, it's possible to still have this code be usable, but
participating in Spring managed transactions. It is preferable to write
your new code using the higher level abstractions mentioned