We will start with a coverage of Hibernate 3 in a Spring environment, using it to demonstrate the approach that Spring takes towards integrating O/R mappers. This section will cover many issues in detail and show different variations of DAO implementations and transaction demarcation. Most of these patterns can be directly translated to all other supported ORM tools. The following sections in this chapter will then cover the other ORM technologies, showing briefer examples there.
Note: As of Spring 2.5, Spring requires Hibernate 3.1 or higher. Neither Hibernate 2.1 nor Hibernate 3.0 are supported anymore.
Typical business applications are often cluttered with repetitive
resource management code. Many projects try to invent their own
solutions for this issue, sometimes sacrificing proper handling of
failures for programming convenience. Spring advocates strikingly simple
solutions for proper resource handling, namely IoC via templating; for
example infrastructure classes with callback interfaces, or applying AOP
interceptors. The infrastructure cares for proper resource handling, and
for appropriate conversion of specific API exceptions to an unchecked
infrastructure exception hierarchy. Spring introduces a DAO exception
hierarchy, applicable to any data access strategy. For direct JDBC, the
JdbcTemplate
class mentioned in a previous
section cares for connection handling, and for proper conversion of
SQLException
to the
DataAccessException
hierarchy, including
translation of database-specific SQL error codes to meaningful exception
classes. It supports both JTA and JDBC transactions, via respective
Spring transaction managers.
Spring also offers Hibernate and JDO support, consisting of a
HibernateTemplate
/
JdoTemplate
analogous to
JdbcTemplate
, a
HibernateInterceptor
/
JdoInterceptor
, and a Hibernate / JDO transaction
manager. The major goal is to allow for clear application layering, with
any data access and transaction technology, and for loose coupling of
application objects. No more business service dependencies on the data
access or transaction strategy, no more hard-coded resource lookups, no
more hard-to-replace singletons, no more custom service registries. One
simple and consistent approach to wiring up application objects, keeping
them as reusable and free from container dependencies as possible. All
the individual data access features are usable on their own but
integrate nicely with Spring's application context concept, providing
XML-based configuration and cross-referencing of plain JavaBean
instances that don't need to be Spring-aware. In a typical Spring
application, many important objects are JavaBeans: data access
templates, data access objects (that use the templates), transaction
managers, business services (that use the data access objects and
transaction managers), web view resolvers, web controllers (that use the
business services),and so on.
To avoid tying application objects to hard-coded resource lookups,
Spring allows you to define resources such as a JDBC
DataSource
or a Hibernate
SessionFactory
as beans in the Spring
container. Application objects that need to access resources just
receive references to such pre-defined instances via bean references
(the DAO definition in the next section illustrates this). The following
excerpt from an XML application context definition shows how to set up a
JDBC DataSource
and a Hibernate
SessionFactory
on top of it:
<beans> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource"/> <property name="mappingResources"> <list> <value>product.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.HSQLDialect </value> </property> </bean> </beans>
Note that switching from a local Jakarta Commons DBCP
BasicDataSource
to a JNDI-located
DataSource
(usually managed by an
application server) is just a matter of configuration:
<beans> <bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="java:comp/env/jdbc/myds"/> </bean> </beans>
You can also access a JNDI-located
SessionFactory
, using Spring's
JndiObjectFactoryBean
to retrieve and expose it.
However, that is typically not common outside of an EJB context.
The basic programming model for templating looks as follows, for
methods that can be part of any custom data access object or business
service. There are no restrictions on the implementation of the
surrounding object at all, it just needs to provide a Hibernate
SessionFactory
. It can get the latter
from anywhere, but preferably as bean reference from a Spring IoC
container - via a simple setSessionFactory(..)
bean property setter. The following snippets show a DAO definition in a
Spring container, referencing the above defined
SessionFactory
, and an example for a DAO
method implementation.
<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> </beans>
public class ProductDaoImpl implements ProductDao { private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); } public Collection loadProductsByCategory(String category) throws DataAccessException { return this.hibernateTemplate.find("from test.Product product where product.category=?", category); } }
The HibernateTemplate
class provides many
methods that mirror the methods exposed on the Hibernate
Session
interface, in addition to a
number of convenience methods such as the one shown above. If you need
access to the Session
to invoke methods
that are not exposed on the HibernateTemplate
,
you can always drop down to a callback-based approach like so.
public class ProductDaoImpl implements ProductDao { private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); } public Collection loadProductsByCategory(final String category) throws DataAccessException { return this.hibernateTemplate.execute(new HibernateCallback() { public Object doInHibernate(Session session) { Criteria criteria = session.createCriteria(Product.class); criteria.add(Expression.eq("category", category)); criteria.setMaxResults(6); return criteria.list(); } }; } }
A callback implementation effectively can be used for any
Hibernate data access. HibernateTemplate
will
ensure that Session
instances are
properly opened and closed, and automatically participate in
transactions. The template instances are thread-safe and reusable, they
can thus be kept as instance variables of the surrounding class. For
simple single step actions like a single find, load, saveOrUpdate, or
delete call, HibernateTemplate
offers alternative
convenience methods that can replace such one line callback
implementations. Furthermore, Spring provides a convenient
HibernateDaoSupport
base class that provides a
setSessionFactory(..)
method for receiving a
SessionFactory
, and
getSessionFactory()
and
getHibernateTemplate()
for use by subclasses. In
combination, this allows for very simple DAO implementations for typical
requirements:
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao { public Collection loadProductsByCategory(String category) throws DataAccessException { return this.getHibernateTemplate().find( "from test.Product product where product.category=?", category); } }
As alternative to using Spring's
HibernateTemplate
to implement DAOs, data access
code can also be written in a more traditional fashion, without wrapping
the Hibernate access code in a callback, while still respecting and
participating in Spring's generic
DataAccessException
hierarchy. The
HibernateDaoSupport
base class offers methods to
access the current transactional Session
and to convert exceptions in such a scenario; similar methods are also
available as static helpers on the
SessionFactoryUtils
class. Note that such code
will usually pass 'false
' as the value of the
getSession(..)
methods
'allowCreate
' argument, to enforce running within a
transaction (which avoids the need to close the returned
Session
, as its lifecycle is managed by
the transaction).
public class HibernateProductDao extends HibernateDaoSupport implements ProductDao { public Collection loadProductsByCategory(String category) throws DataAccessException, MyException { Session session = getSession(false); try { Query query = session.createQuery("from test.Product product where product.category=?"); query.setString(0, category); List result = query.list(); if (result == null) { throw new MyException("No search results."); } return result; } catch (HibernateException ex) { throw convertHibernateAccessException(ex); } } }
The advantage of such direct Hibernate access code is that it
allows any checked application exception to be
thrown within the data access code; contrast this to the
HibernateTemplate
class which is restricted to
throwing only unchecked exceptions within the callback. Note that you
can often defer the corresponding checks and the throwing of application
exceptions to after the callback, which still allows working with
HibernateTemplate
. In general, the
HibernateTemplate
class' convenience methods are
simpler and more convenient for many scenarios.
Hibernate 3 provides a feature called "contextual Sessions", where
Hibernate itself manages one current
Session
per transaction. This is roughly
equivalent to Spring's synchronization of one Hibernate
Session
per transaction. A corresponding
DAO implementation looks like as follows, based on the plain Hibernate
API:
public class ProductDaoImpl implements ProductDao { private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public Collection loadProductsByCategory(String category) { return this.sessionFactory.getCurrentSession() .createQuery("from test.Product product where product.category=?") .setParameter(0, category) .list(); } }
This style is very similar to what you will find in the Hibernate
reference documentation and examples, except for holding the
SessionFactory
in an instance variable.
We strongly recommend such an instance-based setup over the old-school
static
HibernateUtil
class
from Hibernate's CaveatEmptor sample application. (In general, do not
keep any resources in static
variables unless
absolutely necessary.)
The above DAO follows the Dependency Injection pattern: it fits
nicely into a Spring IoC container, just like it would if coded against
Spring's HibernateTemplate
. Of course, such a DAO
can also be set up in plain Java (for example, in unit tests): simply
instantiate it and call setSessionFactory(..)
with the desired factory reference. As a Spring bean definition, it
would look as follows:
<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> </beans>
The main advantage of this DAO style is that it depends on Hibernate API only; no import of any Spring class is required. This is of course appealing from a non-invasiveness perspective, and will no doubt feel more natural to Hibernate developers.
However, the DAO throws plain
HibernateException
(which is unchecked, so does
not have to be declared or caught), which means that callers can only
treat exceptions as generally fatal - unless they want to depend on
Hibernate's own exception hierarchy. Catching specific causes such as an
optimistic locking failure is not possible without tieing the caller to
the implementation strategy. This tradeoff might be acceptable to
applications that are strongly Hibernate-based and/or do not need any
special exception treatment.
Fortunately, Spring's
LocalSessionFactoryBean
supports Hibernate's
SessionFactory.getCurrentSession()
method for
any Spring transaction strategy, returning the current Spring-managed
transactional Session
even with
HibernateTransactionManager
. Of course, the
standard behavior of that method remains: returning the current
Session
associated with the ongoing JTA
transaction, if any (no matter whether driven by Spring's
JtaTransactionManager
, by EJB CMT, or by
JTA).
In summary: DAOs can be implemented based on the plain Hibernate 3 API, while still being able to participate in Spring-managed transactions.
Transactions can be demarcated in a higher level of the
application, on top of such lower-level data access services spanning
any number of operations. There are no restrictions on the
implementation of the surrounding business service here as well, it just
needs a Spring PlatformTransactionManager
. Again,
the latter can come from anywhere, but preferably as bean reference via
a setTransactionManager(..)
method - just like
the productDAO
should be set via a
setProductDao(..)
method. The following
snippets show a transaction manager and a business service definition in
a Spring application context, and an example for a business method
implementation.
<beans> <bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> <bean id="myProductService" class="product.ProductServiceImpl"> <property name="transactionManager" ref="myTxManager"/> <property name="productDao" ref="myProductDao"/> </bean> </beans>
public class ProductServiceImpl implements ProductService { private TransactionTemplate transactionTemplate; private ProductDao productDao; public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionTemplate = new TransactionTemplate(transactionManager); } public void setProductDao(ProductDao productDao) { this.productDao = productDao; } public void increasePriceOfAllProductsInCategory(final String category) { this.transactionTemplate.execute(new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult(TransactionStatus status) { List productsToChange = this.productDao.loadProductsByCategory(category); // do the price increase... } } ); } }
Alternatively, one can use Spring's declarative transaction support, which essentially enables you to replace explicit transaction demarcation API calls in your Java code with an AOP transaction interceptor configured in a Spring container. This allows you to keep business services free of repetitive transaction demarcation code, and allows you to focus on adding business logic which is where the real value of your application lies. Furthermore, transaction semantics like propagation behavior and isolation level can be changed in a configuration file and do not affect the business service implementations.
<beans> <bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> <bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="product.ProductService"/> <property name="target"> <bean class="product.DefaultProductService"> <property name="productDao" ref="myProductDao"/> </bean> </property> <property name="interceptorNames"> <list> <value>myTxInterceptor</value> <!-- the transaction interceptor (configured elsewhere) --> </list> </property> </bean> </beans>
public class ProductServiceImpl implements ProductService { private ProductDao productDao; public void setProductDao(ProductDao productDao) { this.productDao = productDao; } // notice the absence of transaction demarcation code in this method // Spring's declarative transaction infrastructure will be demarcating transactions on your behalf public void increasePriceOfAllProductsInCategory(final String category) { List productsToChange = this.productDao.loadProductsByCategory(category); // ... } }
Spring's TransactionInterceptor
allows any
checked application exception to be thrown with the callback code, while
TransactionTemplate
is restricted to unchecked
exceptions within the callback.
TransactionTemplate
will trigger a rollback in
case of an unchecked application exception, or if the transaction has
been marked rollback-only by the application (via
TransactionStatus
).
TransactionInterceptor
behaves the same way by
default but allows configurable rollback policies per method.
The following higher level approach to declarative transactions
doesn't use the ProxyFactoryBean
, and as such may
be easier to use if you have a large number of service objects that you
wish to make transactional.
![]() | Note |
---|---|
You are strongly encouraged to read the section entitled Section 11.5, “Declarative transaction management” if you have not done so already prior to continuing. |
<?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 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- SessionFactory, DataSource, etc. omitted --> <bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> <aop:config> <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> </aop:config> <tx:advice id="txAdvice" transaction-manager="myTxManager"> <tx:attributes> <tx:method name="increasePrice*" propagation="REQUIRED"/> <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> <tx:method name="*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice> <bean id="myProductService" class="product.SimpleProductService"> <property name="productDao" ref="myProductDao"/> </bean> </beans>
Both TransactionTemplate
and
TransactionInterceptor
delegate the actual
transaction handling to a
PlatformTransactionManager
instance, which can be
a HibernateTransactionManager
(for a single
Hibernate SessionFactory
, using a
ThreadLocal
Session
under the hood) or a
JtaTransactionManager
(delegating to the JTA
subsystem of the container) for Hibernate applications. You could even
use a custom PlatformTransactionManager
implementation. So switching from native Hibernate transaction
management to JTA, such as when facing distributed transaction
requirements for certain deployments of your application, is just a
matter of configuration. Simply replace the Hibernate transaction
manager with Spring's JTA transaction implementation. Both transaction
demarcation and data access code will work without changes, as they just
use the generic transaction management APIs.
For distributed transactions across multiple Hibernate session
factories, simply combine JtaTransactionManager
as a transaction strategy with multiple
LocalSessionFactoryBean
definitions. Each of your
DAOs then gets one specific
SessionFactory
reference passed into its
corresponding bean property. If all underlying JDBC data sources are
transactional container ones, a business service can demarcate
transactions across any number of DAOs and any number of session
factories without special regard, as long as it is using
JtaTransactionManager
as the strategy.
<beans> <bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName value="java:comp/env/jdbc/myds1"/> </bean> <bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="java:comp/env/jdbc/myds2"/> </bean> <bean id="mySessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource1"/> <property name="mappingResources"> <list> <value>product.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true </value> </property> </bean> <bean id="mySessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource2"/> <property name="mappingResources"> <list> <value>inventory.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.OracleDialect </value> </property> </bean> <bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory" ref="mySessionFactory1"/> </bean> <bean id="myInventoryDao" class="product.InventoryDaoImpl"> <property name="sessionFactory" ref="mySessionFactory2"/> </bean> <!-- this shows the Spring 1.x style of declarative transaction configuration --> <!-- it is totally supported, 100% legal in Spring 2.x, but see also above for the sleeker, Spring 2.0 style --> <bean id="myProductService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="myTxManager"/> <property name="target"> <bean class="product.ProductServiceImpl"> <property name="productDao" ref="myProductDao"/> <property name="inventoryDao" ref="myInventoryDao"/> </bean> </property> <property name="transactionAttributes"> <props> <prop key="increasePrice*">PROPAGATION_REQUIRED</prop> <prop key="someOtherBusinessMethod">PROPAGATION_REQUIRES_NEW</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> </beans>
Both HibernateTransactionManager
and
JtaTransactionManager
allow for proper JVM-level
cache handling with Hibernate - without container-specific transaction
manager lookup or JCA connector (as long as not using EJB to initiate
transactions).
HibernateTransactionManager
can export the
JDBC Connection
used by Hibernate to
plain JDBC access code, for a specific
DataSource
. This allows for high-level
transaction demarcation with mixed Hibernate/JDBC data access completely
without JTA, as long as you are just accessing one database!
HibernateTransactionManager
will automatically
expose the Hibernate transaction as JDBC transaction if the passed-in
SessionFactory
has been set up with a
DataSource
(through the "dataSource"
property of the LocalSessionFactoryBean
class).
Alternatively, the DataSource
that the
transactions are supposed to be exposed for can also be specified
explicitly, through the "dataSource" property of the
HibernateTransactionManager
class.
Spring's resource management allows for simple switching between a
JNDI SessionFactory
and a local one,
without having to change a single line of application code. The decision
as to whether to keep the resource definitions in the container or
locally within the application, is mainly a matter of the transaction
strategy being used. Compared to a Spring-defined local
SessionFactory
, a manually registered
JNDI SessionFactory
does not provide any
benefits. Deploying a SessionFactory
through Hibernate's JCA connector provides the added value of
participating in the J2EE server's management infrastructure, but does
not add actual value beyond that.
An important benefit of Spring's transaction support is that it
isn't bound to a container at all. Configured to any other strategy than
JTA, it will work in a standalone or test environment too. Especially
for the typical case of single-database transactions, this is a very
lightweight and powerful alternative to JTA. When using local EJB
Stateless Session Beans to drive transactions, you depend both on an EJB
container and JTA - even if you just access a single database anyway,
and just use SLSBs for declarative transactions via CMT. The alternative
of using JTA programmatically requires a J2EE environment as well. JTA
does not just involve container dependencies in terms of JTA itself and
of JNDI DataSource
instances. For
non-Spring JTA-driven Hibernate transactions, you have to use the
Hibernate JCA connector, or extra Hibernate transaction code with the
TransactionManagerLookup
being configured
for proper JVM-level caching.
Spring-driven transactions can work with a locally defined
Hibernate SessionFactory
nicely, just
like with a local JDBC DataSource
- if
accessing a single database, of course. Therefore you just have to fall
back to Spring's JTA transaction strategy when actually facing
distributed transaction requirements. Note that a JCA connector needs
container-specific deployment steps, and obviously JCA support in the
first place. This is far more hassle than deploying a simple web app
with local resource definitions and Spring-driven transactions. And you
often need the Enterprise Edition of your container, as for example
WebLogic Express does not provide JCA. A Spring application with local
resources and transactions spanning one single database will work in any
J2EE web container (without JTA, JCA, or EJB) - like Tomcat, Resin, or
even plain Jetty. Additionally, such a middle tier can be reused in
desktop applications or test suites easily.
All things considered: if you do not use EJB, stick with local
SessionFactory
setup and Spring's
HibernateTransactionManager
or
JtaTransactionManager
. You will get all of the
benefits including proper transactional JVM-level caching and
distributed transactions, without any container deployment hassle. JNDI
registration of a Hibernate
SessionFactory
via the JCA connector
really only adds value when used in conjunction with EJBs.
In some JTA environments with very strict
XADataSource
implementations -- currently
only some WebLogic and WebSphere versions -- when using Hibernate
configured without any awareness of the JTA
PlatformTransactionManager
object for
that environment, it is possible for spurious warning or exceptions to
show up in the application server log. These warnings or exceptions will
say something to the effect that the connection being accessed is no
longer valid, or JDBC access is no longer valid, possibly because the
transaction is no longer active. As an example, here is an actual
exception from WebLogic:
java.sql.SQLException: The transaction is no longer active - status: 'Committed'. No further JDBC access is allowed within this transaction.
This warning is easy to resolve by simply making Hibernate aware
of the JTA PlatformTransactionManager
instance, to which it will also synchronize (along with Spring). This
may be done in two ways:
If in your application context you are already directly
obtaining the JTA
PlatformTransactionManager
object
(presumably from JNDI via JndiObjectFactoryBean
)
and feeding it for example to Spring's
JtaTransactionManager
, then the easiest way
is to simply specify a reference to this as the value of
LocalSessionFactoryBean
's
jtaTransactionManager property. Spring will
then make the object available to Hibernate.
More likely you do not already have the JTA
PlatformTransactionManager
instance
(since Spring's JtaTransactionManager
can
find it itself) so you need to instead configure Hibernate to also
look it up directly. This is done by configuring an AppServer
specific TransactionManagerLookup
class in the
Hibernate configuration, as described in the Hibernate
manual.
It is not necessary to read any more for proper usage, but the
full sequence of events with and without Hibernate being aware of the
JTA PlatformTransactionManager
will now
be described.
When Hibernate is not configured with any awareness of the JTA
PlatformTransactionManager
, the sequence
of events when a JTA transaction commits is as follows:
JTA transaction commits
Spring's JtaTransactionManager
is
synchronized to the JTA transaction, so it is called back via an
afterCompletion callback by the JTA transaction
manager.
Among other activities, this can trigger a callback by Spring
to Hibernate, via Hibernate's
afterTransactionCompletion
callback (used to
clear the Hibernate cache), followed by an explicit
close()
call on the Hibernate Session, which
results in Hibernate trying to close()
the JDBC
Connection.
In some environments, this
Connection.close()
call then triggers the
warning or error, as the application server no longer considers the
Connection
usable at all, since the
transaction has already been committed.
When Hibernate is configured with awareness of the JTA
PlatformTransactionManager
, the sequence
of events when a JTA transaction commits is instead as follows:
JTA transaction is ready to commit
Spring's JtaTransactionManager
is
synchronized to the JTA transaction, so it is called back via a
beforeCompletion callback by the JTA
transaction manager.
Spring is aware that Hibernate itself is synchronized to the
JTA transaction, and behaves differently than in the previous
scenario. Assuming the Hibernate
Session
needs to be closed at all,
Spring will close it now.
JTA Transaction commits
Hibernate is synchronized to the JTA transaction, so it is called back via an afterCompletion callback by the JTA transaction manager, and can properly clear its cache.