spring-framework/spring-framework-reference/src/orm.xml

2210 lines
110 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="orm">
<title>Object Relational Mapping (ORM) Data Access</title>
<section id="orm-introduction">
<title>Introduction to ORM with Spring</title>
<para>The Spring Framework supports integration
with Hibernate, Java Persistence API (JPA), Java Data Objects (JDO) and
iBATIS SQL Maps for resource management, data access object (DAO)
implementations, and transaction strategies. For example, for Hibernate
there is first-class support with several convenient IoC features that
address many typical Hibernate integration issues. You can configure
all of the supported features for O/R (object relational) mapping tools through
Dependency Injection. They can participate in Spring's resource
and transaction management, and they comply with Spring's generic
transaction and DAO exception hierarchies. The recommended integration
style is to code DAOs against plain Hibernate, JPA, and JDO APIs. The
older style of using Spring's DAO templates is no longer recommended;
however, coverage of this style can be found in the <xref
linkend="classic-spring-orm" /> in the appendices.</para>
<para>Spring adds significant enhancements to the ORM layer of your choice
when you create data access applications. You can leverage as much of the
integration support as you wish, and you should compare this integration
effort with the cost and risk of building a similar infrastructure
in-house. You can use much of the ORM support as you would a library,
regardless of technology, because everything is designed as a set of
reusable JavaBeans. ORM in a Spring IoC container facilitates
configuration and deployment. Thus most examples in this section show
configuration inside a Spring container.</para>
<para>Benefits of using the Spring Framework to create your ORM DAOs
include:</para>
<itemizedlist>
<listitem>
<para><emphasis>Easier testing.</emphasis> Spring's IoC approach makes
it easy to swap the implementations and configuration locations of
Hibernate <interfacename>SessionFactory</interfacename> instances,
JDBC <interfacename>DataSource</interfacename> instances, transaction
managers, and mapped object implementations (if needed). <!--I changed *mappes* to *mapped*; is that what you mean? Also, clarify whether *if needed* refers only to that or to the rest as well
TR: OK. Refers only to mapped object implementations-->This in turn makes it
much easier to test each piece of persistence-related code in
isolation.<!--deleted redundancy; sentence already refers to isolating each piece of code. TR: OK. moved isolation to the end--></para>
</listitem>
<listitem>
<para><emphasis>Common data access exceptions.</emphasis> Spring can
wrap exceptions from your ORM tool, converting them from proprietary
(potentially checked) exceptions to a common runtime
DataAccessException hierarchy. This feature allows you to handle most
persistence exceptions, which are non-recoverable, only in the
appropriate layers, without annoying boilerplate catches, throws, and
exception declarations. You can still trap and handle exceptions as
necessary. Remember that JDBC exceptions (including DB-specific
dialects) are also converted to the same hierarchy, meaning that you
can perform some operations with JDBC within a consistent programming
model.</para>
</listitem>
<listitem>
<para><emphasis>General resource management.</emphasis> Spring
application contexts can handle the location and configuration of
Hibernate <interfacename>SessionFactory</interfacename> instances, JPA
<interfacename>EntityManagerFactory</interfacename> instances, JDBC
<interfacename>DataSource</interfacename> instances, iBATIS SQL Maps
configuration objects, and other related resources. This makes these
values easy to manage and change. Spring offers efficient, easy, and
safe handling of persistence resources. For example, related code that
uses Hibernate generally needs to use the same Hibernate
<interfacename>Session</interfacename> to ensure efficiency and proper
transaction handling. Spring makes it easy to create and bind a
<interfacename>Session</interfacename> to the current thread
transparently, <!--This bullet and next refer to template wrapper class. Is this referring to using Spring DAO templates, whichis no longer recommend--><!--ed? If so, it's confusing to discuss it as an option. Sends a mixed message. If not, explain what you mean by *template* wrapper class.
TR: REVISED, PLS REVIEW. Good point, removed coverage of template wrapper.-->by
exposing a current <interfacename>Session</interfacename> through the
Hibernate <interfacename>SessionFactory</interfacename>. Thus Spring
solves many chronic problems of typical Hibernate usage, for any local
or JTA transaction environment.</para>
</listitem>
<listitem>
<para><emphasis>Integrated transaction management.</emphasis> You can
wrap your ORM code with a declarative, aspect-oriented programming
(AOP) style method interceptor either through the
<interfacename>@Transactional</interfacename> annotation or by
explicitly configuring the transaction AOP advice in an XML
configuration file. In both cases, transaction semantics and exception
handling (rollback, and so on) are handled for you. As discussed
below, in <!--Instead of *below*, provide link to section. TR: OK--><link
linkend="orm-resource-mngmnt">Resource and transaction
management</link>, you can also swap various transaction managers,
without affecting your ORM-related code. For example, you can swap
between local transactions and JTA, with the same full services (such
as declarative transactions) available in both scenarios.
Additionally, JDBC-related code can fully integrate transactionally
with the code you use to do ORM. This is useful for data access that
is not suitable for ORM, such as batch processing and BLOB streaming,
which still need <!--if both batch processing and BLOB streaming need to share common transactions w/ ORM, then change *needs* to *to need*. If --><!--it refers only to BLOB streaming, say *the latter of which still needs to share...* TR: OK. Chnaged to *to need*-->to
share common transactions with ORM operations.</para>
</listitem>
</itemizedlist>
<para><!--The PetClinic sample in the Spring distribution offers alternative DAO implementations and application context configurations for JDBC,
Hibernate, and JPA. PetClinic is a working sample application that illustrates the use of Hibernate and JPA in a Spring web application.
It also leverages declarative transaction demarcation with different transaction strategies.
Beyond the samples shipped with Spring, vendors provide a variety of Spring-based ORM samples. --><!--Name vendors, link to them? TR: WILL ADDRESS LATER. We need to point to the current samples which aren't completed yet. --><emphasis>TODO:
provide links to current samples</emphasis></para>
</section>
<section id="orm-general">
<title>General ORM integration considerations</title>
<para>This section highlights considerations that apply to all ORM
technologies. The <xref linkend="orm-hibernate" /> section provides more
details and also show these features and configurations in a concrete
context.</para>
<para>The major goal of Spring's ORM integration is 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 need not be Spring-aware. In a typical Spring application, many
important objects are JavaBeans: data access templates, data access
objects, 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.</para>
<section id="orm-resource-mngmnt">
<title>Resource and transaction management</title>
<para>Typical business applications are cluttered with repetitive
resource management code. Many projects try to invent their own
solutions, sometimes sacrificing proper handling of failures for
programming convenience. Spring advocates simple solutions for proper
resource handling, namely IoC through templating<!--same question as before re templates. Does preceding refer to Spring templates that in beginning you say you no longer recommend?
TR: OK AS IS. The template for JDBC is still recommended--> in the case of
JDBC and applying AOP interceptors for the ORM technologies.</para>
<para>The infrastructure provides proper resource handling and
appropriate conversion of specific API exceptions to an unchecked
infrastructure exception hierarchy. <!--What do you mean by *cares for*? I substituted *provides*. Should it be *implements*? TR: OK-->Spring
introduces a DAO exception hierarchy, applicable to any data access
strategy. For direct JDBC, the <classname>JdbcTemplate</classname> class
mentioned in a previous section provides connection handling and proper
conversion of <classname>SQLException</classname> to the
<classname>DataAccessException</classname> hierarchy, including
translation of database-specific SQL error codes to meaningful exception
classes. For ORM technologies, see the next section for how to get the
same exception translation benefits.</para>
<para>When it comes to transaction management, the
<classname>JdbcTemplate</classname> class hooks in to the Spring
transaction support and supports both JTA and JDBC transactions, through
respective Spring transaction managers. For the supported ORM
technologies Spring offers Hibernate, JPA and JDO support through the
Hibernate, JPA, and JDO transaction managers as well as JTA support. For
details on transaction support, see the <xref linkend="transaction" />
chapter.</para>
</section>
<section id="orm-exception-translation">
<title>Exception translation</title>
<para>When you use Hibernate, JPA, or JDO in a DAO, you must decide how
to handle the persistence technology's native exception classes. The DAO
throws a subclass of a <classname>HibernateException</classname>,
<classname>PersistenceException</classname> or
<interfacename>JDOException</interfacename> depending on the technology.
These exceptions are all run-time exceptions and do not have to be
declared or caught. You may also have to deal with
<classname>IllegalArgumentException</classname> and
<classname>IllegalStateException</classname>. This means that callers
can only treat exceptions as generally fatal, unless they want to depend
on the persistence technology's own exception structure. Catching
specific causes such as an optimistic locking failure is not possible
without tying the caller to the implementation strategy. This trade off
might be acceptable to applications that are strongly ORM-based and/or
do not need any special exception treatment. However, Spring enables
exception translation to be applied transparently through the
<interfacename>@Repository</interfacename> annotation:</para>
<programlisting language="java">@Repository
public class ProductDaoImpl implements ProductDao {
<lineannotation>// class body here...</lineannotation>
}</programlisting>
<programlisting language="xml">&lt;beans&gt;
<lineannotation>&lt;!-- <classname>Exception</classname> translation bean post processor --&gt;</lineannotation>
&lt;bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"/&gt;
&lt;/beans&gt;</programlisting>
<para>The postprocessor automatically looks for all exception
translators (implementations of the
<interfacename>PersistenceExceptionTranslator</interfacename> interface)
and advises all beans marked with the
<interfacename>@Repository</interfacename> annotation so that the
discovered translators can intercept and apply the appropriate
translation on the thrown exceptions.</para>
<para>In summary: you can implement DAOs based on the plain persistence
technology's API and annotations, while still benefiting from
Spring-managed transactions, dependency injection, and transparent
exception conversion (if desired) to Spring's custom exception
hierarchies.</para>
</section>
</section>
<section id="orm-hibernate">
<title>Hibernate</title>
<para>We will start with a coverage of <ulink
url="http://www.hibernate.org/">Hibernate 3</ulink> 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.</para>
<para><note>
<para>As of Spring 2.5, Spring requires Hibernate 3.1 or later.
Neither Hibernate 2.1 nor Hibernate 3.0 are supported.</para>
</note></para>
<section id="orm-session-factory-setup">
<title><interfacename>SessionFactory</interfacename> setup in a Spring
container</title>
<para>To avoid tying application objects to hard-coded resource lookups,
you can define resources such as a JDBC
<interfacename>DataSource</interfacename> or a Hibernate
<interfacename>SessionFactory</interfacename> as beans in the Spring
container. Application objects that need to access resources receive
references to such predefined instances through bean references, as
illustrated in the DAO definition in the next section.</para>
<para>The following excerpt from an XML application context definition
shows how to set up a JDBC <classname>DataSource</classname> and a
Hibernate <interfacename>SessionFactory</interfacename> on top of
it:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt;
&lt;property name="driverClassName" value="org.hsqldb.jdbcDriver"/&gt;
&lt;property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/&gt;
&lt;property name="username" value="sa"/&gt;
&lt;property name="password" value=""/&gt;
&lt;/bean&gt;
&lt;bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;
&lt;property name="dataSource" ref="myDataSource"/&gt;
&lt;property name="mappingResources"&gt;
&lt;list&gt;
&lt;value&gt;product.hbm.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="hibernateProperties"&gt;
&lt;value&gt;
hibernate.dialect=org.hibernate.dialect.HSQLDialect
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>Switching from a local Jakarta Commons DBCP
<classname>BasicDataSource</classname> to a JNDI-located
<interfacename>DataSource</interfacename> (usually managed by an
application server) is just a matter of configuration:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/&gt;
&lt;/beans&gt;</programlisting>
<para>You can also access a JNDI-located
<interfacename>SessionFactory</interfacename>, using Spring's
<classname>JndiObjectFactoryBean</classname> /
<literal>&lt;jee:jndi-lookup&gt;</literal> to retrieve and expose it.
However, that is typically not common outside of an EJB context.</para>
</section>
<section id="orm-hibernate-straight">
<title>Implementing DAOs based on plain Hibernate 3 API</title>
<para>Hibernate 3 has a feature called contextual sessions, wherein
Hibernate itself manages one current
<interfacename>Session</interfacename> per transaction. This is roughly
equivalent to Spring's synchronization of one Hibernate
<interfacename>Session</interfacename> per transaction. A corresponding
DAO implementation resembles the following example, based on the plain
Hibernate API:</para>
<programlisting language="java">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();
}
}</programlisting>
<para>This style is similar to that of the Hibernate reference
documentation and examples, except for holding the
<interfacename>SessionFactory</interfacename> in an instance variable.
We strongly recommend such an instance-based setup over the old-school
<literal>static</literal> <classname>HibernateUtil</classname> class
from Hibernate's CaveatEmptor sample application. (In general, do not
keep any resources in <literal>static</literal> variables unless
<emphasis>absolutely</emphasis> necessary.)</para>
<para>The above DAO follows the dependency injection pattern: it fits
nicely into a Spring IoC container, just as it would if coded against
Spring's <classname>HibernateTemplate</classname>. Of course, such a DAO
can also be set up in plain Java (for example, in unit tests). Simply
instantiate it and call <methodname>setSessionFactory(..)</methodname>
with the desired factory reference. As a Spring bean definition, the DAO
would resemble the following:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="sessionFactory" ref="mySessionFactory"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>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.</para>
<para>However, the DAO throws plain
<classname>HibernateException</classname> (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 tying the caller to
the implementation strategy. This trade off might be acceptable to
applications that are strongly Hibernate-based and/or do not need any
special exception treatment.</para>
<para>Fortunately, Spring's
<classname>LocalSessionFactoryBean</classname> supports Hibernate's
<methodname>SessionFactory.getCurrentSession()</methodname> method for
any Spring transaction strategy, returning the current Spring-managed
transactional <interfacename>Session</interfacename> even with
<classname>HibernateTransactionManager</classname>. Of course, the
standard behavior of that method remains the return of the current
<interfacename>Session</interfacename> associated with the ongoing JTA
transaction, if any. This behavior applies regardless of whether you are
using Spring's <classname>JtaTransactionManager</classname>, EJB
container managed transactions (CMTs), or JTA.</para>
<para>In summary: you can implement DAOs based on the plain Hibernate 3
API, while still being able to participate in Spring-managed
transactions.</para>
</section>
<section id="orm-hibernate-tx-declarative">
<title>Declarative transaction demarcation</title>
<para>We recommend that you use Spring's declarative transaction
support, which enables you to replace explicit transaction demarcation
API calls in your Java code with an AOP transaction interceptor. This
transaction interceptor can be configured in a Spring container using
either Java annotations or XML.<!--Reword last part of preceding sentence to clarify *what* is *using Java annotations or XML*. Are you using Java annotations or XML to replace--><!--explicit transaction demarcation API calls, etc. OR are you saying the Spring container is using these?
TR: REVISED, PLS REVIEW.-->This declarative transaction capability allows you
to keep business services free of repetitive transaction demarcation
code and to focus on adding business logic, which is the real value of
your application.</para>
<note>
<para>Prior to continuing, you are <emphasis>strongly</emphasis>
encouraged to read <xref linkend="transaction-declarative" /> if you
have not done so.</para>
</note>
<para>Furthermore, transaction semantics like propagation behavior and
isolation level can be changed in a configuration file and do not affect
the business service implementations.<!--give context to example; what is it showing, what is its purpose? TR: REVISED, PLS REVIEW. Added some context.--></para>
<para>The following example shows how you can configure an AOP
transaction interceptor, using XML, for a simple service class:</para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;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-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"&gt;
<lineannotation>&lt;!-- <interfacename>SessionFactory</interfacename>, <interfacename>DataSource</interfacename>, etc. omitted --&gt;</lineannotation>
&lt;bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt;
&lt;property name="sessionFactory" ref="sessionFactory"/&gt;
&lt;/bean&gt;
&lt;aop:config&gt;
&lt;aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/&gt;
&lt;aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/&gt;
&lt;/aop:config&gt;
&lt;tx:advice id="txAdvice" transaction-manager="myTxManager"&gt;
&lt;tx:attributes&gt;
&lt;tx:method name="increasePrice*" propagation="REQUIRED"/&gt;
&lt;tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/&gt;
&lt;tx:method name="*" propagation="SUPPORTS" read-only="true"/&gt;
&lt;/tx:attributes&gt;
&lt;/tx:advice&gt;
&lt;bean id="myProductService" class="product.SimpleProductService"&gt;
&lt;property name="productDao" ref="myProductDao"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>This is the service class that is advised:</para>
<programlisting language="java">public class ProductServiceImpl implements ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
<lineannotation>// notice the absence of transaction demarcation code in this method</lineannotation>
<lineannotation>// Spring's declarative transaction infrastructure will be demarcating transactions on your behalf </lineannotation>
public void increasePriceOfAllProductsInCategory(final String category) {
List productsToChange = this.productDao.loadProductsByCategory(category);
<lineannotation>// ...</lineannotation>
}
}</programlisting>
<para>We also show an attribute-support based configuration, in the
following example. <!--I added *in the following example*; is this correct? Relate example below to the one that follows it. TR: OK-->You
annotate the service layer with @Transactional annotations and instruct
the Spring container to find these annotations and provide transactional
semantics for these annotated methods.</para>
<programlisting language="java">public class ProductServiceImpl implements ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
@Transactional
public void increasePriceOfAllProductsInCategory(final String category) {
List productsToChange = this.productDao.loadProductsByCategory(category);
<lineannotation>// ...</lineannotation>
}
@Transactional(readOnly = true)
public List&lt;Product&gt; findAllProducts() {
return this.productDao.findAllProducts();
}
}</programlisting>
<para>As you can see from the following configuration example, the
configuration is much simplified, compared to the XML example above,
while still providing the same functionality driven by the annotations
in the service layer code. All you need to provide is the
TransactionManager implementation and a "&lt;tx:annotation-driven/&gt;"
entry.<!--What does preceding example show, what's its relation to this example? TR: REVISED, PLS REVIEW.--></para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;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-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"&gt;
<lineannotation>&lt;!-- <interfacename>SessionFactory</interfacename>, <interfacename>DataSource</interfacename>, etc. omitted --&gt;</lineannotation>
&lt;bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt;
&lt;property name="sessionFactory" ref="sessionFactory"/&gt;
&lt;/bean&gt;
&lt;tx:annotation-driven/&gt;
&lt;bean id="myProductService" class="product.SimpleProductService"&gt;
&lt;property name="productDao" ref="myProductDao"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
</section>
<section id="orm-hibernate-tx-programmatic">
<title>Programmatic transaction demarcation</title>
<para>You can demarcate transactions in a higher level of the
application, on top of such lower-level data access services spanning
any number of operations. Nor do restrictions exist on the
implementation of the surrounding business service; it just needs a
Spring <classname>PlatformTransactionManager</classname>. Again, the
latter can come from anywhere, but preferably as a bean reference
through a <methodname>setTransactionManager(..)</methodname> method,
just as the <classname>productDAO</classname> should be set by a
<methodname>setProductDao(..)</methodname> 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:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt;
&lt;property name="sessionFactory" ref="mySessionFactory"/&gt;
&lt;/bean&gt;
&lt;bean id="myProductService" class="product.ProductServiceImpl"&gt;
&lt;property name="transactionManager" ref="myTxManager"/&gt;
&lt;property name="productDao" ref="myProductDao"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<programlisting language="java">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);
<lineannotation>// do the price increase...</lineannotation>
}
}
);
}
}</programlisting>
<para>Spring's <classname>TransactionInterceptor</classname> allows any
checked application exception to be thrown with the callback code, while
<classname>TransactionTemplate</classname> is restricted to unchecked
exceptions within the callback.
<classname>TransactionTemplate</classname> triggers a rollback in case
of an unchecked application exception, or if the transaction is marked
rollback-only by the application (via
<classname>TransactionStatus</classname>).
<classname>TransactionInterceptor</classname> behaves the same way by
default but allows configurable rollback policies per method.</para>
</section>
<section id="orm-hibernate-tx-strategies">
<title>Transaction management strategies</title>
<para>Both <classname>TransactionTemplate</classname> and
<classname>TransactionInterceptor</classname> delegate the actual
transaction handling to a
<classname>PlatformTransactionManager</classname> instance, which can be
a <classname>HibernateTransactionManager</classname> (for a single
Hibernate <interfacename>SessionFactory</interfacename>, using a
<classname>ThreadLocal</classname>
<interfacename>Session</interfacename> under the hood) or a
<classname>JtaTransactionManager</classname> (delegating to the JTA
subsystem of the container) for Hibernate applications. You can even use
a custom <classname>PlatformTransactionManager</classname>
implementation. 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, because they just use
the generic transaction management APIs.</para>
<para>For distributed transactions across multiple Hibernate session
factories, simply combine <classname>JtaTransactionManager</classname>
as a transaction strategy with multiple
<classname>LocalSessionFactoryBean</classname> definitions. Each DAO
then gets one specific <interfacename>SessionFactory</interfacename>
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
<classname>JtaTransactionManager</classname> as the strategy.</para>
<programlisting language="xml">&lt;beans&gt;
&lt;jee:jndi-lookup id="dataSource1" jndi-name="java:comp/env/jdbc/myds1"/&gt;
&lt;jee:jndi-lookup id="dataSource2" jndi-name="java:comp/env/jdbc/myds2"/&gt;
&lt;bean id="mySessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;
&lt;property name="dataSource" ref="myDataSource1"/&gt;
&lt;property name="mappingResources"&gt;
&lt;list&gt;
&lt;value&gt;product.hbm.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="hibernateProperties"&gt;
&lt;value&gt;
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="mySessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;
&lt;property name="dataSource" ref="myDataSource2"/&gt;
&lt;property name="mappingResources"&gt;
&lt;list&gt;
&lt;value&gt;inventory.hbm.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="hibernateProperties"&gt;
&lt;value&gt;
hibernate.dialect=org.hibernate.dialect.OracleDialect
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="sessionFactory" ref="mySessionFactory1"/&gt;
&lt;/bean&gt;
&lt;bean id="myInventoryDao" class="product.InventoryDaoImpl"&gt;
&lt;property name="sessionFactory" ref="mySessionFactory2"/&gt;
&lt;/bean&gt;
&lt;bean id"myProductService" class="product.ProductServiceImpl"&gt;
&lt;property name="productDao" ref="myProductDao"/&gt;
&lt;property name="inventoryDao" ref="myInventoryDao"/&gt;
&lt;/bean&gt;
&lt;aop:config&gt;
&lt;aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/&gt;
&lt;aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/&gt;
&lt;/aop:config&gt;
&lt;tx:advice id="txAdvice" transaction-manager="myTxManager"&gt;
&lt;tx:attributes&gt;
&lt;tx:method name="increasePrice*" propagation="REQUIRED"/&gt;
&lt;tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/&gt;
&lt;tx:method name="*" propagation="SUPPORTS" read-only="true"/&gt;
&lt;/tx:attributes&gt;
&lt;/tx:advice&gt;
&lt;/beans&gt;</programlisting>
<para>Both <classname>HibernateTransactionManager</classname> and
<classname>JtaTransactionManager</classname> allow for proper JVM-level
cache handling with Hibernate, without container-specific transaction
manager lookup or a JCA connector (if you are not using EJB to initiate
transactions).<!--Is it clear that the parenthetical phrase applies to only *JCA connector* or does it apply to *without transaction manager lookup* also?
TR: OK. Reads OK to me, it applies to both. --></para>
<para><classname>HibernateTransactionManager</classname> can export the
Hibernate JDBC <interfacename>Connection</interfacename> to plain JDBC
access code, for a specific <interfacename>DataSource</interfacename>.
This capability allows for high-level transaction demarcation with mixed
Hibernate and JDBC data access completely without JTA, if you are
accessing only one database.
<classname>HibernateTransactionManager</classname> automatically exposes
the Hibernate transaction as a JDBC transaction if you have set up the
passed-in <interfacename>SessionFactory</interfacename> with a
<interfacename>DataSource</interfacename> through the
<classname>dataSource</classname> property of the
<classname>LocalSessionFactoryBean</classname> class. Alternatively, you
can specify explicitly the <interfacename>DataSource</interfacename> for
which the transactions are supposed to be exposed through the
<classname>dataSource</classname> property of the
<classname>HibernateTransactionManager</classname> class.</para>
</section>
<section id="orm-hibernate-resources">
<title>Comparing container-managed and locally defined resources<!--I've revised to better communicate the point of the section, which I think has to do with --><!--comparing spring's local support for transactions as opposed to container support. Revise as necessary.
TR: REVISED, PLS REVIEW. Changed to heading *resources* since it technically could be more than transactions i.e. caching--></title>
<para>You can switch between a container-managed JNDI
<interfacename>SessionFactory</interfacename><!--Clarify whether JNDI SessionFactory refers to container resources; I'm not sure what's being compared.
TR: REVISED, PLS REVIEW. Clarified by addin container-managed.--> and a
locally defined one, without having to change a single line of
application code. Whether to keep resource definitions in the container
or locally within the application is mainly a matter of the transaction
strategy that you use. Compared to a Spring-defined local
<interfacename>SessionFactory</interfacename>, a manually registered
JNDI <interfacename>SessionFactory</interfacename> does not provide any
benefits. Deploying a <interfacename>SessionFactory</interfacename>
through Hibernate's JCA connector provides the added value of
participating in the Java EE server's management infrastructure, but
does not add actual value beyond that.</para>
<para>Spring's transaction support is not bound to a container.
Configured with any strategy other than JTA, transaction support also
works in a stand-alone or test environment. Especially in the typical
case of single-database transactions, Spring's single-resource local
transaction support <!--I wrote *stand-alone transaction support*; if not correct, specify what you mean by *this*.
TR: REVISED, PLS REVIEW. Changed to single-resource local transaction support.-->is
a lightweight and powerful alternative to JTA. When you use local EJB
stateless session beans to drive transactions, you depend both on an EJB
container and JTA, even if you access only a single database, and only
use stateless session beans to provide declarative transactions through
container-managed transactions. <!--Does the next sentence refer to Spring or non-Spring? Clarify. I'm not sure whether the point of this paragraph and preceding is clear.
TR: REVISED, PLS REVIEW. It's not very clear. I've revised it. It refers to non-Spring programmatic use of JTA.-->Also,
direct use of JTA programmatically requires a Java EE environment as
well. JTA does not involve only container dependencies in terms of JTA
itself and of JNDI <interfacename>DataSource</interfacename> instances.
For non-Spring, JTA-driven Hibernate transactions, you have to use the
Hibernate JCA connector, or extra Hibernate transaction code with the
<interfacename>TransactionManagerLookup</interfacename> configured for
proper JVM-level caching.</para>
<para>Spring-driven transactions can work as well with a locally defined
Hibernate <interfacename>SessionFactory</interfacename> as they do with
a local JDBC <interfacename>DataSource </interfacename>if they are
accessing a single database. Thus you only have to use Spring's JTA
transaction strategy when you have distributed transaction requirements.
A JCA connector requires container-specific deployment steps, and
obviously JCA support in the first place. This configuration requires
more work than deploying a simple web application with local resource
definitions and Spring-driven transactions. Also, you often need the
Enterprise Edition of your container if you are using, for example,
WebLogic Express, which does not provide JCA. A Spring application with
local resources and transactions spanning one single database works in
any Java EE web container (without JTA, JCA, or EJB) such as Tomcat,
Resin, or even plain Jetty. Additionally, you can easily reuse such a
middle tier in desktop applications or test suites.</para>
<para>All things considered, if you do not use EJBs, stick with local
<interfacename>SessionFactory</interfacename> setup and Spring's
<classname>HibernateTransactionManager</classname> or
<classname>JtaTransactionManager</classname>. You get all of the
benefits, including proper transactional JVM-level caching and
distributed transactions, without the inconvenience of container
deployment. JNDI registration of a Hibernate
<interfacename>SessionFactory</interfacename> through the JCA connector
only adds value when used in conjunction with EJBs.</para>
</section>
<section id="orm-hibernate-invalid-jdbc-access-error">
<title>Spurious application server warnings with Hibernate</title>
<para>In some JTA environments with very strict
<interfacename>XADataSource</interfacename> implementations -- currently
only some WebLogic Server and WebSphere versions -- when Hibernate is
configured without regard to the JTA
<interfacename>PlatformTransactionManager</interfacename> object for
that environment, it is possible for spurious warning or exceptions to
show up in the application server log. These warnings or exceptions
indicate 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:</para>
<programlisting>java.sql.SQLException: The transaction is no longer active - status: 'Committed'.
No further JDBC access is allowed within this transaction.</programlisting>
<para>You resolve this warning by simply making Hibernate aware of the
JTA <interfacename>PlatformTransactionManager</interfacename> instance,
to which it will synchronize (along with Spring). You have two options
for doing this:</para>
<itemizedlist>
<listitem>
<para>If in your application context you are already directly
obtaining the JTA
<interfacename>PlatformTransactionManager</interfacename> object
(presumably from JNDI through
<literal>JndiObjectFactoryBean/<literal>&lt;jee:jndi-lookup&gt;</literal></literal>)
and feeding it, for example, to Spring's
<classname>JtaTransactionManager</classname>, then the easiest way
is to specify a reference to the bean defining this JTA
<interfacename>PlatformTransactionManager</interfacename>
instance<!--Replace *this* with exactly what *this* refes to--> as
the value of the <property>jtaTransactionManager</property> property
for <classname>LocalSessionFactoryBea.</classname> Spring then makes
the object available to Hibernate.</para>
</listitem>
<listitem>
<para>More likely you do not already have the JTA
<interfacename>PlatformTransactionManager</interfacename> instance,
because Spring's <classname>JtaTransactionManager</classname> can
find it itself. <!--Re preceding sentence, if this is the case, then why would you need to do what first bullet describes?
TR: OK AS IS. This is very container dependent, and either case is possible.-->Thus
you need to configure Hibernate to look up JTA
<interfacename>PlatformTransactionManager</interfacename> directly.
You do this by configuring an application server- specific
<literal>TransactionManagerLookup</literal> class in the Hibernate
configuration, as described in the Hibernate manual.</para>
</listitem>
</itemizedlist>
<para>The remainder of this section describes the sequence of events
that occur with and without Hibernate's awareness of the JTA
<interfacename>PlatformTransactionManager</interfacename>.</para>
<para>When Hibernate is not configured with any awareness of the JTA
<interfacename>PlatformTransactionManager</interfacename>, the following
events occur when a JTA transaction commits:</para>
<orderedlist>
<listitem>
<para>The JTA transaction commits.</para>
</listitem>
<listitem>
<para>Spring's <classname>JtaTransactionManager</classname> is
synchronized to the JTA transaction, so it is called back through an
<emphasis>afterCompletion</emphasis> callback by the JTA transaction
manager.</para>
</listitem>
<listitem>
<para>Among other activities, this synchronization<!--Identify *this*. TR: REVISED, PLS REVIEW. Added "synchronization"-->can
trigger a callback by Spring to Hibernate, through Hibernate's
<literal>afterTransactionCompletion</literal> callback <!--Preceding line, is *afterTransactionCompletion* callback the same as *afterCompletion* callback in step 2? If so, revise so --><!--there is no redundancy, or at least refer to the two callbacks in the same way.
TR: OK AS IS. Two different callback methhods - one is Spring's (*afterCompletion*) and the other is Hibernate's (*afterTransactionCompletion*)-->(used
to clear the Hibernate cache), followed by an explicit
<literal>close()</literal> call on the Hibernate Session, which
causes Hibernate to attempt to <literal>close()</literal> the JDBC
Connection.</para>
</listitem>
<listitem>
<para>In some environments, this
<methodname>Connection.close()</methodname> call then triggers the
warning or error, as the application server no longer considers the
<interfacename>Connection</interfacename> usable at all, because the
transaction has already been committed.</para>
</listitem>
</orderedlist>
<para>When Hibernate is configured with awareness of the JTA
<interfacename>PlatformTransactionManager</interfacename>, the following
events occur when a JTA transaction commits:</para>
<orderedlist>
<listitem>
<para>the JTA transaction is ready to commit.</para>
</listitem>
<listitem>
<para>Spring's <classname>JtaTransactionManager</classname> is
synchronized to the JTA transaction, so the transaction is called
back through a <emphasis>beforeCompletion</emphasis> callback by the
JTA transaction manager.</para>
</listitem>
<listitem>
<para>Spring is aware that Hibernate itself is synchronized to the
JTA transaction, and behaves differently than in the previous
scenario. Assuming the Hibernate
<interfacename>Session</interfacename> needs to be closed at all,
Spring will close it now.</para>
</listitem>
<listitem>
<para>The JTA transaction commits.</para>
</listitem>
<listitem>
<para>Hibernate is synchronized to the JTA transaction, so the
transaction is called back through an
<emphasis>afterCompletion</emphasis> callback by the JTA transaction
manager, and can properly clear its cache.</para>
</listitem>
</orderedlist>
</section>
</section>
<section id="orm-jdo">
<title>JDO</title>
<para>Spring supports the standard JDO 2.0 and 2.1 APIs as data access
strategy, following the same style as the Hibernate support. The
corresponding integration classes reside in the
<literal>org.springframework.orm.jdo</literal> package.</para>
<section id="orm-jdo-setup">
<title><interfacename>PersistenceManagerFactory</interfacename>
setup</title>
<para>Spring provides a
<classname>LocalPersistenceManagerFactoryBean</classname> class that
allows you to define a local JDO
<interfacename>PersistenceManagerFactory</interfacename> within a Spring
application context:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"&gt;
&lt;property name="configLocation" value="classpath:kodo.properties"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>Alternatively, you can set up a
<interfacename>PersistenceManagerFactory</interfacename> through direct
instantiation of a
<interfacename>PersistenceManagerFactory</interfacename> implementation
class. A JDO <interfacename>PersistenceManagerFactory</interfacename>
implementation class follows the JavaBeans pattern, just like a JDBC
<interfacename>DataSource</interfacename> implementation class, which is
a natural fit for a configuration that uses Spring. This setup style
usually supports a Spring-defined JDBC
<interfacename>DataSource</interfacename>, passed into the
<classname>connectionFactory</classname> property. For example, for the
open source JDO implementation DataNucleus (formerly JPOX) (<ulink
url="http://www.datanucleus.org/">http://www.datanucleus.org/</ulink>),
this is the XML configuration of the
<interfacename>PersistenceManagerFactory</interfacename>
implementation:<!--complete the intro sentence; what does this example show? What is its purpose? TR: REVISED, PLS REVIEW.--></para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt;
&lt;property name="driverClassName" value="${jdbc.driverClassName}"/&gt;
&lt;property name="url" value="${jdbc.url}"/&gt;
&lt;property name="username" value="${jdbc.username}"/&gt;
&lt;property name="password" value="${jdbc.password}"/&gt;
&lt;/bean&gt;
&lt;bean id="myPmf" class="org.datanucleus.jdo.JDOPersistenceManagerFactory" destroy-method="close"&gt;
&lt;property name="connectionFactory" ref="dataSource"/&gt;
&lt;property name="nontransactionalRead" value="true"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>You can also set up JDO
<interfacename>PersistenceManagerFactory</interfacename> in the JNDI
environment of a Java EE application server, usually through the JCA
connector provided by the particular JDO implementation. Spring's
standard <literal>JndiObjectFactoryBean /
<literal>&lt;jee:jndi-lookup&gt;</literal></literal> can be used to
retrieve and expose such a
<interfacename>PersistenceManagerFactory</interfacename>. However,
outside an EJB context, no real benefit exists in holding the
<interfacename>PersistenceManagerFactory</interfacename> in JNDI: only
choose such a setup for a good reason. See <xref
linkend="orm-hibernate-resources" /> for a discussion; the arguments
there apply to JDO as well.</para>
</section>
<section id="orm-jdo-daos-straight">
<title>Implementing DAOs based on the plain JDO API</title>
<para>DAOs can also be written directly against plain JDO API, without
any Spring dependencies, by using an injected
<interfacename>PersistenceManagerFactory</interfacename>. The following
is an example of a corresponding DAO implementation:</para>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
try {
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
return query.execute(category);
}
finally {
pm.close();
}
}
}</programlisting>
<para>Because the above DAO follows the dependency injection pattern, it
fits nicely into a Spring container, just as it would if coded against
Spring's <classname>JdoTemplate</classname>:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="persistenceManagerFactory" ref="myPmf"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>The main problem with such DAOs is that they always get a new
<interfacename>PersistenceManager</interfacename> from the factory. To
access a Spring-managed transactional
<interfacename>PersistenceManager</interfacename>, define a
<classname>TransactionAwarePersistenceManagerFactoryProxy</classname>
(as included in Spring) in front of your target
<interfacename>PersistenceManagerFactory</interfacename>, then passing a
reference to that proxy into your DAOs as in the following example:<!--Revise to clarify *what* is passing the proxy into DAOs? How does that relate to rest of the sentence? TR: REVISED, PLS REVIEW.--></para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myPmfProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"&gt;
&lt;property name="targetPersistenceManagerFactory" ref="myPmf"/&gt;
&lt;/bean&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="persistenceManagerFactory" ref="myPmfProxy"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>Your data access code will receive a transactional
<interfacename>PersistenceManager</interfacename> (if any) from the
<methodname>PersistenceManagerFactory.getPersistenceManager()</methodname>
method that it calls. The latter method call goes through the proxy,
which first checks for a current transactional
<interfacename>PersistenceManager</interfacename> before getting a new
one from the factory. Any <methodname>close()</methodname> calls on the
<interfacename>PersistenceManager</interfacename> are ignored in case of
a transactional
<interfacename>PersistenceManager</interfacename>.</para>
<para>If your data access code always runs within an active transaction
(or at least within active transaction synchronization), it is safe to
omit the <methodname>PersistenceManager.close()</methodname> call and
thus the entire <literal>finally</literal> block, which you might do to
keep your DAO implementations concise:</para>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
return query.execute(category);
}
}</programlisting>
<para>With such DAOs that rely on active transactions, it is recommended
that you enforce active transactions through turning off
<classname>TransactionAwarePersistenceManagerFactoryProxy</classname>'s
<classname>allowCreate</classname> flag:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myPmfProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"&gt;
&lt;property name="targetPersistenceManagerFactory" ref="myPmf"/&gt;
&lt;property name="allowCreate" value="false"/&gt;
&lt;/bean&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="persistenceManagerFactory" ref="myPmfProxy"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>The main advantage of this DAO style is that it depends on JDO API
only; no import of any Spring class is required. This is of course
appealing from a non-invasiveness perspective, and might feel more
natural to JDO developers.</para>
<para>However, the DAO throws plain
<exceptionname>JDOException</exceptionname> (which is unchecked, so does
not have to be declared or caught), which means that callers can only
treat exceptions as fatal, unless you want to depend on JDO's own
exception structure. Catching specific causes such as an optimistic
locking failure is not possible without tying the caller to the
implementation strategy. This trade off might be acceptable to
applications that are strongly JDO-based and/or do not need any special
exception treatment.</para>
<para>In summary, you can DAOs based on the plain JDO API, and they can
still participate in Spring-managed transactions. This strategy might
appeal to you if you are already familiar with JDO. However, such DAOs
throw plain <exceptionname>JDOException</exceptionname>, and you would
have to convert explicitly to Spring's
<exceptionname>DataAccessException</exceptionname> (if desired).</para>
</section>
<section id="orm-jdo-tx">
<title>Transaction management</title>
<note>
<para>You are <emphasis>strongly</emphasis> encouraged to read <xref
linkend="transaction-declarative" /> if you have not done so, to get a
more detailed coverage of Spring's declarative transaction
support.</para>
</note>
<para>To execute service operations within transactions, you can use
Spring's common declarative transaction facilities. For example:</para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;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-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"&gt;
&lt;bean id="myTxManager" class="org.springframework.orm.jdo.JdoTransactionManager"&gt;
&lt;property name="persistenceManagerFactory" ref="myPmf"/&gt;
&lt;/bean&gt;
&lt;bean id="myProductService" class="product.ProductServiceImpl"&gt;
&lt;property name="productDao" ref="myProductDao"/&gt;
&lt;/bean&gt;
&lt;tx:advice id="txAdvice" transaction-manager="txManager"&gt;
&lt;tx:attributes&gt;
&lt;tx:method name="increasePrice*" propagation="REQUIRED"/&gt;
&lt;tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/&gt;
&lt;tx:method name="*" propagation="SUPPORTS" read-only="true"/&gt;
&lt;/tx:attributes&gt;
&lt;/tx:advice&gt;
&lt;aop:config&gt;
&lt;aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/&gt;
&lt;aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/&gt;
&lt;/aop:config&gt;
&lt;/beans&gt;</programlisting>
<para>JDO requires an active transaction to modify a persistent object.
The non-transactional flush concept does not exist in JDO, in contrast
to Hibernate. For this reason, you need to set up the chosen JDO
implementation for a specific environment. Specifically, you need to set
it up explicitly for JTA synchronization, to detect an active JTA
transaction itself. This is not necessary for local transactions as
performed by Spring's <classname>JdoTransactionManager</classname>, but
it is necessary to participate in JTA transactions, whether driven by
Spring's <classname>JtaTransactionManager</classname> or by EJB CMT and
plain JTA.</para>
<para><classname>JdoTransactionManager</classname> is capable of
exposing a JDO transaction to JDBC access code that accesses the same
JDBC <interfacename>DataSource</interfacename>, provided that the
registered <classname>JdoDialect</classname> supports retrieval of the
underlying JDBC <interfacename>Connection</interfacename>. This is the
case for JDBC-based JDO 2.0 implementations by default.</para>
</section>
<section id="orm-jdo-dialect">
<title><interfacename>JdoDialect</interfacename></title>
<para>As an advanced feature, both <classname>JdoTemplate</classname>
and <classname>JdoTransactionManager</classname> support a custom
<interfacename>JdoDialect</interfacename> that can be passed into the
<code>jdoDialect</code> bean property. In this scenario, the DAOs will
not receive a <interfacename>PersistenceManagerFactory</interfacename>
reference but rather a full <classname>JdoTemplate</classname> instance
(for example, passed into the <literal>jdoTemplate</literal>
property of <classname>JdoDaoSupport</classname>). Using a
<interfacename>JdoDialect</interfacename> implementation, you can enable
advanced features supported by Spring, usually in a vendor-specific
manner:</para>
<itemizedlist>
<listitem>
<para>Applying specific transaction semantics such as custom
isolation level or transaction timeout</para>
</listitem>
<listitem>
<para>Retrieving the transactional JDBC
<interfacename>Connection</interfacename> for exposure to JDBC-based
DAOs</para>
</listitem>
<listitem>
<para>Applying query timeouts, which are automatically calculated
from Spring-managed transaction timeouts</para>
</listitem>
<listitem>
<para>Eagerly flushing a
<interfacename>PersistenceManager,</interfacename> to make
transactional changes visible to JDBC-based data access code</para>
</listitem>
<listitem>
<para>Advanced translation of <literal>JDOExceptions</literal> to
Spring <literal>DataAccessExceptions</literal></para>
</listitem>
</itemizedlist>
<para>See the <classname>JdoDialect</classname> Javadoc for more details
on its operations and how to use them within Spring's JDO
support.</para>
</section>
</section>
<section id="orm-jpa">
<title>JPA</title>
<para>The Spring JPA, available under the
<literal>org.springframework.orm.jpa</literal> package, offers
comprehensive support for the <ulink
url="http://java.sun.com/developer/technicalArticles/J2EE/jpa/index.html">Java
Persistence API</ulink> in a similar manner to the integration with
Hibernate or JDO, while being aware of the underlying implementation in
order to provide additional features.</para>
<section id="orm-jpa-setup">
<title>Three options for JPA setup in a Spring environment</title>
<para>The Spring JPA support offers three ways of setting up the JPA
<interfacename>EntityManagerFactory</interfacename> that will be used by
the application to obtain an entity manager.<!--Define and give purpose of JPA EntityManagerFactory. TR: REVISED, PLS REVIEW.--></para>
<section id="orm-jpa-setup-lemfb">
<title><classname>LocalEntityManagerFactoryBean</classname></title>
<note>
<para>Only use this option in simple deployment environments such as
stand-alone applications and integration tests.</para>
</note>
<para>The <classname>LocalEntityManagerFactoryBean</classname> creates
an <interfacename>EntityManagerFactory</interfacename> suitable for
simple deployment environments where the application uses only JPA for
data access. <!--Note says use option only for stand-alone apps and testing; does that conflict with preceding line re data access?
TR: REVISED, PLS REVIEW.-->The factory bean uses the JPA
<interfacename>PersistenceProvider</interfacename> autodetection
mechanism (according to JPA's Java SE bootstrapping) and, in most
cases, requires you to specify only the persistence unit name:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"&gt;
&lt;property name="persistenceUnitName" value="myPersistenceUnit"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>This form of JPA deployment is the simplest and the most
limited. You cannot refer <!--cannot link *what* to an existing datasource? TR: REVISED, PLS REVIEW.-->to
an existing JDBC <interfacename>DataSource</interfacename> bean
definition and no support for global transactions exists. Furthermore,
weaving (byte-code transformation) of persistent classes is
provider-specific, often requiring a specific JVM agent to specified
on startup. This option is sufficient only for stand-alone
applications and test environments, for which the JPA specification is
designed.</para>
</section>
<section id="orm-jpa-setup-jndi">
<title>Obtaining an <classname>EntityManagerFactory</classname> from
JNDI</title>
<note>
<para>Use this option when deploying to a Java EE 5 server. Check
your server's documentation on how to deploy a custom JPA provider
into your server, allowing for a different provider than the
server's default.</para>
</note>
<para>Obtaining an <interfacename>EntityManagerFactory</interfacename>
from JNDI (for example in a Java EE 5 environment), is simply a matter
of changing the XML configuration:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/&gt;
&lt;/beans&gt;</programlisting>
<para>This action assumes standard Java EE 5 bootstrapping: the Java
EE server autodetects persistence units (in effect,
<literal>META-INF/persistence.xml</literal> files in application jars)
and <literal>persistence-unit-ref</literal> entries in the Java EE
deployment descriptor (for example, <literal>web.xml</literal>) and
defines environment naming context locations for those persistence
units.</para>
<para>In such a scenario, the entire persistence unit deployment,
including the weaving (byte-code transformation) of persistent
classes, is up to the Java EE server. The JDBC
<interfacename>DataSource</interfacename> is defined through a JNDI
location in the <literal>META-INF/persistence.xml</literal> file;
EntityManager transactions are integrated with the server's JTA
subsystem. Spring merely uses the obtained
<interfacename>EntityManagerFactory</interfacename>, passing it on to
application objects through dependency injection, and managing
transactions for the persistence unit,<!--identify *it* TR: REVISED, PLS REVIEW. Added *persistence unit*-->
typically through <classname>JtaTransactionManager</classname>.</para>
<para>If multiple persistence units are used in the same application,
the bean names of such JNDI-retrieved persistence units should match
the persistence unit names that the application uses to refer to them,
for example, in <literal>@PersistenceUnit</literal> and
<literal>@PersistenceContext</literal> annotations.</para>
</section>
<section id="orm-jpa-setup-lcemfb">
<title><classname>LocalContainerEntityManagerFactoryBean</classname></title>
<note>
<para>Use this option for full JPA capabilities in a Spring-based
application environment. This includes web containers such as Tomcat
as well as stand-alone applications and integration tests with
sophisticated persistence requirements.</para>
</note>
<para>The
<classname>LocalContainerEntityManagerFactoryBean</classname> gives
full control over <interfacename>EntityManagerFactory</interfacename>
configuration and is appropriate for environments where fine-grained
customization is required. The
<classname>LocalContainerEntityManagerFactoryBean</classname> creates
a <interfacename>PersistenceUnitInfo</interfacename> instance<!--A PersistenceUnitInfo *what*? TR: REVISED, PLS REVIEW. Added *instance*. -->based
on the <literal>persistence.xml</literal> file, the supplied
<literal>dataSourceLookup</literal> strategy, and the specified
<literal>loadTimeWeaver</literal>. It is thus possible to work with
custom data sources outside of JNDI and to control the weaving
process. The following example shows a typical bean definition for a
<interfacename>LocalContainerEntityManagerFactoryBean</interfacename>:<!--The following examples shows what? What's its purpose? TR: REVISED, PLS REVIEW.--></para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
&lt;property name="dataSource" ref="someDataSource"/&gt;
&lt;property name="loadTimeWeaver"&gt;
&lt;bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>The following example shows a typical
<literal>persistence.xml</literal> file:</para>
<programlisting language="xml">&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"&gt;
&lt;persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL"&gt;
&lt;mapping-file&gt;META-INF/orm.xml&lt;/mapping-file&gt;
&lt;exclude-unlisted-classes/&gt;
&lt;/persistence-unit&gt;
&lt;/persistence&gt;</programlisting>
<note>
<para>The <code>exclude-unlisted-classes</code> element always
indicates that <emphasis>no</emphasis> scanning for annotated entity
classes is supposed to occur, in order to support the
<code>&lt;exclude-unlisted-classes/&gt;</code> shortcut. This is in
line with the JPA specification, which suggests that shortcut, but
unfortunately is in conflict with the JPA XSD, which implies
<code>false</code> for that shortcut. Consequently,
<code>&lt;exclude-unlisted-classes&gt; false
&lt;/exclude-unlisted-classes/&gt;</code> is not supported. Simply
omit the <code>exclude-unlisted-classes</code> element if you want
entity class scanning to occur.</para>
</note>
<para>Using the
<classname>LocalContainerEntityManagerFactoryBean</classname> is the
most powerful JPA setup option, allowing for flexible local
configuration within the application. It supports links to an existing
JDBC <interfacename>DataSource</interfacename>, supports both local
and global transactions, and so on. However, it also imposes
requirements on the runtime environment, such as the availability <!--Clarify: first says it imposes *requirements* but says such as *the availability* of a weaving-capable Classloader. Revise to say--><!--whether you are *required* to use this when persistence provider demands byte-code transformation. i.e. what is the *requirement* here?
TR: OK AS IS. The requirement is to provide the classloader for the runtime environment, if necessary - this is configured outside of Spring.-->of
a weaving-capable class loader if the persistence provider demands
byte-code transformation.</para>
<para>This option may conflict with the built-in JPA capabilities of a
Java EE 5 server. In a full Java EE 5 environment, consider obtaining
your <interfacename>EntityManagerFactory</interfacename> from JNDI.
Alternatively, specify a custom
<classname>persistenceXmlLocation</classname> on your
<classname>LocalContainerEntityManagerFactoryBean</classname>
definition, for example, META-INF/my-persistence.xml, and only include
a descriptor with that name in your application jar files. Because the
Java EE 5 server only looks for default
<literal>META-INF/persistence.xml</literal> files, it ignores such
custom persistence units and hence avoid conflicts with a
Spring-driven JPA setup upfront. (This applies to Resin 3.1, for
example.)</para>
<sidebar>
<title>When is load-time weaving required?</title>
<para>Not all JPA providers require a JVM agent ; Hibernate is an
example of one that does not. If your provider does not require an
agent or you have other alternatives, such as applying enhancements
at build time through a custom compiler or an ant task, the
load-time weaver <emphasis role="bold">should not</emphasis> be
used.</para>
</sidebar>
<para>The <interfacename>LoadTimeWeaver</interfacename> interface is a
Spring-provided class that allows JPA
<interfacename>ClassTransformer</interfacename> instances to be
plugged in a specific manner, depending whether the environment is a
web container or application server. <!--Preceding: is this what you mean? Avoid slashes (web container/application server); slashes mean different things depending on context.--><!--Revise if necessary. TR: OK.-->
Hooking <literal>ClassTransformers</literal> through a Java 5 <ulink
url="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/instrument/package-summary.html">agent</ulink>
typically is not efficient. The agents work against the
<emphasis>entire virtual machine</emphasis> and inspect
<emphasis>every</emphasis> class that is loaded, which is usually
undesirable in a production server environment.</para>
<para>Spring provides a number of
<interfacename>LoadTimeWeaver</interfacename> implementations for
various environments, allowing
<interfacename>ClassTransformer</interfacename> instances to be
applied only <emphasis>per class loader</emphasis> and not per
VM.</para>
<para>The following sections will discuss typical JPA weaving setup on
Tomcat and with Spring's VM agent. See <xref
linkend="aop-aj-ltw-spring" /> in the AOP chapter for details on how
to set up general load-time weaving with Tomcat, the VM agent,
WebLogic, OC4J, GlassFish, and Resin.</para>
<section id="orm-jpa-setup-lcemfb-tomcat">
<title>Tomcat load-time weaving setup (5.0+)</title>
<para><ulink url="http://tomcat.apache.org/">Apache Tomcat's</ulink>
default class loader does not support class transformation but does
allow the use of custom class loaders. Spring offers the
<classname>TomcatInstrumentableClassLoader</classname> (in the
<literal>org.springframework.instrument.classloading.tomcat</literal>
package), which extends the Tomcat class loader
(<classname>WebappClassLoader</classname>), and allows JPA
<classname>ClassTransformer</classname> instances to enhance all
classes loaded by it. In short, JPA transformers are applied only
inside a specific web application that uses the
<classname>TomcatInstrumentableClassLoader</classname>.</para>
<para>To use the custom class loader on:</para>
<itemizedlist>
<listitem>
<para>Tomcat 5.0.x/5.5.x</para>
</listitem>
<orderedlist>
<listitem>
<para>Copy <literal>spring-tomcat-weaver.jar</literal> into
<emphasis>$CATALINA_HOME</emphasis>/server/lib,where
<emphasis>$CATALINA_HOME</emphasis> represents the root of the
Tomcat installation.</para>
</listitem>
<listitem>
<para>Instruct Tomcat to use the custom class loader instead
of the default one by editing the web application context
file:</para>
<programlisting language="xml">&lt;Context path="/myWebApp" docBase="/my/webApp/location"&gt;
&lt;Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/&gt;
&lt;/Context&gt;</programlisting>
<para>Tomcat 5.0.x and 5.5.x series support several context
locations: <!--Revise following sentences so it's clear what the context locations are. As written, it's hard to distinguish how many --><!--locations there are.Seems like only two, not *several*. TR: OK AS IS. There are four locations mentioned.-->server
configuration file
(<emphasis>$CATALINA_HOME/conf/server.xml</emphasis>), the
default context configuration
(<emphasis>$CATALINA_HOME/conf/context.xml</emphasis>) that
affects all deployed web applications and per-web application
configurations, <!--CHanged per-webapp to per-web application. If that's not right, what does it mean?-->deployed
on the server
<emphasis>($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml</emphasis>)
side or inside the web application
(<emphasis>your-webapp.war/META-INF/context.xml</emphasis>).
For efficiency, inside the web-app configuration style<!--Which of the preceding is *inside the web-app config style*? Two paths contain webapp.
TR: REVISED, PLS REVIEW. Chnaged the last one to *inside*--> is recommended
because only applications that use JPA will use the custom c
lass loader. See the Tomcat 5.x <ulink
url="http://tomcat.apache.org/tomcat-5.5-doc/config/context.html">documentation</ulink>
for more details about available context locations.</para>
<para>Tomcat versions prior to 5.5.20 contained a bug in the
XML configuration parsing that prevented usage of the
<literal>Loader</literal> tag inside
<emphasis>server.xml</emphasis>, regardless of whether a class
loader is specified or whether it is the official or a custom
one. See Tomcat's bugzilla for <ulink
url="http://issues.apache.org/bugzilla/show_bug.cgi?id=39704">more
details</ulink>.<!--Will reader know what Tomcat's bugzilla is and where to find it? TR: OK AS IS. They just need to click on the hyerlink.--></para>
<para>In Tomcat 5.5.20 or later, you can set
<emphasis>useSystemClassLoaderAsParent</emphasis> to
<literal>false</literal> to fix the problem: <programlisting
language="xml">&lt;Context path="/myWebApp" docBase="/my/webApp/location"&gt;
&lt;Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
useSystemClassLoaderAsParent="false"/&gt;
&lt;/Context&gt;</programlisting></para>
</listitem>
</orderedlist>
<listitem>
<para>Tomcat 6.0.x</para>
</listitem>
<orderedlist>
<listitem>
<para>Copy <literal>spring-tomcat-weaver.jar</literal> into
<emphasis>$CATALINA_HOME</emphasis>/lib, where
<emphasis>$CATALINA_HOME</emphasis> represents the root of the
Tomcat installation)</para>
</listitem>
<listitem>
<para>Instruct Tomcat to use the custom class loader (instead
of the default) by editing the web application context
file:</para>
<programlisting language="xml">&lt;Context path="/myWebApp" docBase="/my/webApp/location"&gt;
&lt;Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/&gt;
&lt;/Context&gt;</programlisting>
<para>The Tomcat 6.0.x (similar to 5.0.x/5.5.x) series
supports several context locations: <!--same as before; I can't tell what the different context locations are. It seems like there are only two, not *several*.
TR: OK AS IS. See above.-->server configuration file
(<emphasis>$CATALINA_HOME/conf/server.xml</emphasis>), the
default context configuration
(<emphasis>$CATALINA_HOME/conf/context.xml</emphasis>) that
affects all deployed web applications and per-web application
configurations, <!--change to per-web application? TR: OK.-->deployed
on the server
<emphasis>($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml</emphasis>)
side or inside the web application
(<emphasis>your-webapp.war/META-INF/context.xml</emphasis>).
For efficiency, inside the web-app configuration style <!--Which one is inside the web-app config style? Reword. TR: REVISED, PLS REVIEW. Same change as for 5.0/5.5-->is
recommended because only applications that use JPA will use
the custom class loader. See the Tomcat 6.0.x <ulink
url="http://tomcat.apache.org/tomcat-6.0-doc/config/context.html">documentation</ulink>
for more details about available context locations.</para>
</listitem>
</orderedlist>
</itemizedlist>
<para>The last step required on all Tomcat versions is to use the
appropriate <interfacename>LoadTimeWeaver</interfacename> when you
configure
<classname>LocalContainerEntityManagerFactoryBean</classname>:</para>
<programlisting language="xml">&lt;bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
&lt;property name="loadTimeWeaver"&gt;
&lt;bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting>
<para>Using this technique, JPA applications relying on
instrumentation, and can run in Tomcat without needing an agent.
This is important especially when Tomcat is hosting applications
that rely on different JPA implementations because the JPA
transformers are applied only at class loader level and thus are
isolated from each other.</para>
<note>
<para>If you use TopLink Essentials as a JPA provider under
Tomcat, place the toplink-essentials JAR under
<emphasis>$CATALINA_HOME</emphasis>/shared/lib folder instead of
inside your war.<!--Revise: *instead of placing the JAR under your WAR*, OR *instead of placing WAR under $CATALINA_HOME/etc*?
TR: REVISED, PLS REVIEW. Should be *inside your war*.--></para>
</note>
</section>
<section id="orm-jpa-setup-lcemfb-agent">
<title>General load-time weaving with the VM agent</title>
<para>For environments that require class instrumentation but are
not supported by the existing <classname>LoadTimeWeaver</classname>
implementations<!--OK? If you mean environments that are not supported by existing impl, revise as shown. If you mean class instrumentation is not supp--><!--orted, say *For environments that require class instrumentation that is not supported...*-->,
a JDK agent can be the only solution. For such cases, Spring
provides <classname>InstrumentationLoadTimeWeaver,</classname> which
requires a Spring-specific (but very general) VM agent, <filename
class="libraryfile">spring-agent.jar</filename>:</para>
<programlisting language="xml">&lt;bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
&lt;property name="loadTimeWeaver"&gt;
&lt;bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting>
<para>You must start the virtual machine with the Spring agent, by
supplying the following JVM options:</para>
<programlisting>-javaagent:/path/to/spring-agent.jar</programlisting>
</section>
<section id="orm-jpa-setup-lcemfb-weaver">
<title>Context-wide load-time weaver setup</title>
<para>In Spring 2.5 and later, you can configure a context-wide
<interfacename>LoadTimeWeaver</interfacename> using the
<literal>context:load-time-weaver</literal> configuration element.
Such a global weaver is picked up by all JPA
<classname>LocalContainerEntityManagerFactoryBeans</classname>
automatically.</para>
<para>This is the preferred way of setting up a load-time weaver,
delivering autodetection of the platform (WebLogic, OC4J, GlassFish,
Tomcat, Resin, or VM agent) and automatic propagation of the weaver
to all weaver-aware beans.</para>
<programlisting language="xml">&lt;context:load-time-weaver/&gt;
&lt;bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
...
&lt;/bean&gt;</programlisting>
<para>See <xref linkend="aop-aj-ltw-spring" /> for details on how to
set up general load-time weaving, covering Tomcat and the VM agent
as well as WebLogic, OC4J, GlassFish and Resin.</para>
</section>
</section>
<section id="orm-jpa-multiple-pu">
<title>Dealing with multiple persistence units</title>
<para>For applications that rely on multiple persistence units
locations, stored in various JARS in the classpath, for example,
Spring offers the
<interfacename>PersistenceUnitManager</interfacename> to act as a
central repository and to avoid the persistence units discovery
process, which can be expensive. The default implementation allows
multiple locations to be specified that are parsed and later retrieved
through the persistence unit name. (By default, the classpath is
searched for <filename>META-INF/persistence.xml</filename>
files.)</para>
<programlisting language="xml">&lt;bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"&gt;
&lt;property name="persistenceXmlLocation"&gt;
&lt;list&gt;
&lt;value&gt;org/springframework/orm/jpa/domain/persistence-multi.xml&lt;/value&gt;
&lt;value&gt;classpath:/my/package/**/custom-persistence.xml&lt;/value&gt;
&lt;value&gt;classpath*:META-INF/persistence.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="dataSources"&gt;
&lt;map&gt;
&lt;entry key="localDataSource" value-ref="local-db"/&gt;
&lt;entry key="remoteDataSource" value-ref="remote-db"/&gt;
&lt;/map&gt;
&lt;/property&gt;
<lineannotation>&lt;!-- if no datasource is specified, use this one --&gt;</lineannotation>
&lt;property name="defaultDataSource" ref="remoteDataSource"/&gt;
&lt;/bean&gt;
&lt;bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
&lt;property name="persistenceUnitManager" ref="pum"/&gt;
&lt;/bean&gt;</programlisting>
<para>The default implementation allows customization of the
<interfacename>PersistenceUnitInfo</interfacename> instances,<!--What is *infos*? information? Clarify. TR: REVISED, PLS REVIEW.-->
before they are fed to the JPA provider, declaratively through its
<!--through what's properties? JPA provider's? TR: OK AS IS. It's the PersistenceUnitManager default implementation's properties-->properties,
which affect <emphasis>all</emphasis> hosted units, or
programmatically, through the
<interfacename>PersistenceUnitPostProcessor</interfacename>, which
allows persistence unit selection. If no
<interfacename>PersistenceUnitManager</interfacename> is specified,
one is created and used internally by
<classname>LocalContainerEntityManagerFactoryBean</classname>.</para>
</section>
</section>
<section id="orm-jpa-straight">
<title>Implementing DAOs based on plain JPA</title>
<note>
<para>Although <interfacename>EntityManagerFactory</interfacename>
instances are thread-safe,
<interfacename>EntityManager</interfacename> instances are not. The
injected JPA <interfacename>EntityManager</interfacename> behaves like
an <interfacename>EntityManager</interfacename> fetched from an
application server's JNDI environment, as defined by the JPA
specification. It delegates all calls to the current transactional
<interfacename>EntityManager</interfacename>, if any; otherwise, it
falls back to a newly created
<interfacename>EntityManager</interfacename> per operation, in effect
making its usage thread-safe.<!--Seems contradictory. First sentence says EntityManager instances are not thread-safe; last sentence refers to use--><!--of EntityManager as thread-safe. TR: REVISED, PLS REVIEW.--></para>
</note>
<para>It is possible to write code against the plain JPA without any
Spring dependencies, by using an injected
<interfacename>EntityManagerFactory</interfacename> or
<interfacename>EntityManager</interfacename>. Spring can understand
<interfacename>@PersistenceUnit</interfacename> and
<interfacename>@PersistenceContext</interfacename> annotations both at
field and method level if a
<classname>PersistenceAnnotationBeanPostProcessor</classname> is
enabled. A plain JPA DAO implementation using the
<interfacename>@PersistenceUnit</interfacename> annotation <!--corresponding to what? TR: REVISED, PLS REVIEW.-->might
look like this:</para>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
private EntityManagerFactory emf;
@PersistenceUnit
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.emf = emf;
}
public Collection loadProductsByCategory(String category) {
EntityManager em = this.emf.createEntityManager();
try {
Query query = em.createQuery("from Product as p where p.category = ?1");
query.setParameter(1, category);
return query.getResultList();
}
finally {
if (em != null) {
em.close();
}
}
}
}</programlisting>
<para>The DAO above has no dependency on Spring and still fits nicely
into a Spring application context. Moreover, the DAO takes advantage of
annotations to require the injection of the default
<interfacename>EntityManagerFactory</interfacename>:</para>
<programlisting language="xml">&lt;beans&gt;
<lineannotation>&lt;!-- bean post-processor for JPA annotations --&gt;</lineannotation>
&lt;bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"/&gt;
&lt;/beans&gt;</programlisting>
<para>As an alternative to defining a
<classname>PersistenceAnnotationBeanPostProcessor</classname>
explicitly, consider using the Spring
<literal>context:annotation-config</literal> XML element in your
application context configuration. Doing so automatically registers all
Spring standard post-processors for annotation-based configuration,
including <classname>CommonAnnotationBeanPostProcessor</classname> and
so on.</para>
<programlisting language="xml">&lt;beans&gt;
<lineannotation>&lt;!-- post-processors for all standard config annotations --&gt;</lineannotation>
&lt;context:annotation-config/&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"/&gt;
&lt;/beans&gt;</programlisting>
<para>The main problem with such a DAO is that it always creates a new
<interfacename>EntityManager</interfacename> through the factory. You
can avoid this by requesting a transactional
<interfacename>EntityManager</interfacename> (also called "shared
EntityManager" because it is a shared, thread-safe proxy for the actual
transactional EntityManager) to be injected instead of the
factory:</para>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
@PersistenceContext
private EntityManager em;
public Collection loadProductsByCategory(String category) {
Query query = em.createQuery("from Product as p where p.category = :category");
query.setParameter("category", category);
return query.getResultList();
}
}</programlisting>
<para>The <literal>@PersistenceContext</literal> annotation has an
optional attribute <literal>type</literal>, which defaults to
<literal>PersistenceContextType.TRANSACTION</literal>. This default is
what you need to receive a shared EntityManager proxy. The alternative,
<literal>PersistenceContextType.EXTENDED</literal>, is a completely
different affair: This results in a so-called extended EntityManager,
which is <emphasis>not thread-safe</emphasis> and hence must not be used
in a concurrently accessed component such as a Spring-managed singleton
bean. Extended EntityManagers are only supposed to be used in stateful
components that, for example, reside in a session, with the lifecycle of
the EntityManager not tied to a current transaction but rather being
completely up to the application.</para>
<sidebar>
<title>Method- and field-level Injection</title>
<para>Annotations that indicate dependency injections (such as
<literal>@PersistenceUnit</literal> and
<literal>@PersistenceContext</literal>) can be applied on field or
methods inside a class, hence the expressions <emphasis>method-level
injection</emphasis> and <emphasis>field-level injection</emphasis>.
Field-level annotations are concise and easier to use while
method-level allows for further processing of the injected dependency.
In both cases the member visibility (public, protected, private) does
not matter.</para>
<para>What about class-level annotations?</para>
<para>On the Java EE 5 platform, they are used for dependency
declaration and not for resource injection.</para>
</sidebar>
<para>The injected <interfacename>EntityManager</interfacename> is
Spring-managed (aware of the ongoing transaction). It is important to
note that even though the new DAO implementation uses method level
injection of an <interfacename>EntityManager</interfacename> instead of
an <interfacename>EntityManagerFactory</interfacename>, no change is
required in the application context XML due to annotation usage.<!--I changed *prefers* to *works better with*. Revise if needed, but an impl. doesn't *prefer*. Also *what* is due to annotation usage; what does--><!--this refer to? TR: REVISED, PLS REVIEW.--></para>
<para>The main advantage of this DAO style is that it only depends on
Java Persistence API; no import of any Spring class is required.
Moreover, as the JPA annotations are understood, the injections are
applied automatically by the Spring container. This is appealing from a
non-invasiveness perspective, and might feel more natural to JPA
developers.</para>
</section>
<section id="orm-jpa-tx">
<title>Transaction Management</title>
<note>
<para>You are <emphasis>strongly</emphasis> encouraged to read <xref
linkend="transaction-declarative" /> if you have not done so, to get a
more detailed coverage of Spring's declarative transaction
support.</para>
</note>
<para>To execute service operations within transactions, you can use
Spring's common declarative transaction facilities. For example:</para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;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-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"&gt;
&lt;bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager"&gt;
&lt;property name="entityManagerFactory" ref="myEmf"/&gt;
&lt;/bean&gt;
&lt;bean id="myProductService" class="product.ProductServiceImpl"&gt;
&lt;property name="productDao" ref="myProductDao"/&gt;
&lt;/bean&gt;
&lt;aop:config&gt;
&lt;aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/&gt;
&lt;aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/&gt;
&lt;/aop:config&gt;
&lt;tx:advice id="txAdvice" transaction-manager="myTxManager"&gt;
&lt;tx:attributes&gt;
&lt;tx:method name="increasePrice*" propagation="REQUIRED"/&gt;
&lt;tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/&gt;
&lt;tx:method name="*" propagation="SUPPORTS" read-only="true"/&gt;
&lt;/tx:attributes&gt;
&lt;/tx:advice&gt;
&lt;/beans&gt;</programlisting>
<para>Spring JPA allows a configured
<classname>JpaTransactionManager</classname> to expose a JPA transaction
to JDBC access code that accesses the same JDBC
<interfacename>DataSource</interfacename>, provided that the registered
<interfacename>JpaDialect</interfacename> supports retrieval of the
underlying JDBC <interfacename>Connection</interfacename>. Out of the
box, Spring provides dialects for the Toplink, Hibernate and OpenJPA JPA
implementations. See the next section for details on the
<interfacename>JpaDialect</interfacename> mechanism.</para>
</section>
<section id="orm-jpa-dialect">
<title><interfacename>JpaDialect</interfacename></title>
<para>As an advanced feature <classname>JpaTemplate</classname>,
<classname>JpaTransactionManager</classname> and subclasses of
<classname>AbstractEntityManagerFactoryBean</classname> support a custom
<interfacename>JpaDialect</interfacename>, to be passed into the
<property>jpaDialect</property> bean property. In such a scenario, the
DAOs do not receive an
<interfacename>EntityManagerFactory</interfacename> reference but rather
a full <classname>JpaTemplate</classname> instance (for example,
passed<!--Clarify *what* is passed? Reword this for example phrase. TR: OK AS-->
into the <property>jpaTemplate</property> property<classname> of
JpaDaoSupport</classname>). A <interfacename>JpaDialect</interfacename>
implementation can enable some advanced features supported by Spring,
usually in a vendor-specific manner:</para>
<itemizedlist>
<listitem>
<para>Applying specific transaction semantics such as custom
isolation level or transaction timeout)</para>
</listitem>
<listitem>
<para>Retrieving the transactional JDBC
<interfacename>Connection</interfacename> for exposure to JDBC-based
DAOs)</para>
</listitem>
<listitem>
<para>Advanced translation of
<literal>PersistenceExceptions</literal> to Spring
<literal>DataAccessExceptions</literal></para>
</listitem>
</itemizedlist>
<para>This is particularly valuable for special transaction semantics
and for advanced translation of exception. The default implementation
used (<classname>DefaultJpaDialect</classname>) does not provide any
special capabilities and if the above features are required, you have to
specify the appropriate dialect.</para>
<para>See the <interfacename>JpaDialect</interfacename> Javadoc for more
details of its operations and how they are used within Spring's JPA
support.</para>
</section>
</section>
<section id="orm-ibatis">
<title>iBATIS SQL Maps</title>
<para>The iBATIS support in the Spring Framework much resembles the JDBC
support in that it supports the same template style programming, and as
with JDBC and other ORM technologies, the iBATIS support works with
Spring's exception hierarchy and lets you enjoy Spring's IoC
features.</para>
<para>Transaction management can be handled through Spring's standard
facilities. No special transaction strategies are necessary for iBATIS,
because no special transactional resource involved other than a JDBC
<interfacename>Connection</interfacename>. Hence, Spring's standard JDBC
<classname>DataSourceTransactionManager</classname> or
<classname>JtaTransactionManager</classname> are perfectly
sufficient.</para>
<note>
<para>Spring supports iBATIS 2.x. The iBATIS 1.x support classes are no
longer provided.<!--directed where? TR: REVISED, PLS REVIEW.--></para>
</note>
<section id="orm-ibatis-setup">
<title>Setting up the <classname>SqlMapClient</classname></title>
<para>Using iBATIS SQL Maps involves creating SqlMap configuration files
containing statements and result maps. Spring takes care of loading
those using the <classname>SqlMapClientFactoryBean</classname>. For the
examples we will be using the following <classname>Account</classname>
class:</para>
<programlisting language="xml">public class Account {
private String name;
private String email;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
}</programlisting>
<para>To map this <classname>Account</classname> class<!--*previous account class*:Identify the account class and the section you're talking about
TR: REVISED, PLS REVIEW. The Account class was part of the iBATIS 1.0 examples that were dropped a long time ago. No one has complained.
Makes you wonder if anyone actually reads thes docs :)--> with iBATIS 2.x we
need to create the following SQL map
<filename>Account.xml</filename>:</para>
<programlisting language="xml">&lt;sqlMap namespace="Account"&gt;
&lt;resultMap id="result" class="examples.Account"&gt;
&lt;result property="name" column="NAME" columnIndex="1"/&gt;
&lt;result property="email" column="EMAIL" columnIndex="2"/&gt;
&lt;/resultMap&gt;
&lt;select id="getAccountByEmail" resultMap="result"&gt;
select ACCOUNT.NAME, ACCOUNT.EMAIL
from ACCOUNT
where ACCOUNT.EMAIL = #value#
&lt;/select&gt;
&lt;insert id="insertAccount"&gt;
insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
&lt;/insert&gt;
&lt;/sqlMap&gt;</programlisting>
<para>The configuration file for iBATIS 2 looks like this:</para>
<programlisting language="xml">&lt;sqlMapConfig&gt;
&lt;sqlMap resource="example/Account.xml"/&gt;
&lt;/sqlMapConfig&gt;</programlisting>
<para>Remember that iBATIS loads resources from the class path, so be
sure to add the<filename>Account.xml</filename> file to the class
path.</para>
<para>We can use the <classname>SqlMapClientFactoryBean</classname> in
the Spring container. Note that with iBATIS SQL Maps 2.x, the JDBC
<interfacename>DataSource</interfacename> is usually specified on the
<classname>SqlMapClientFactoryBean</classname>, which enables lazy
loading. This is the configuration needed for these bean
definitions:<!--Need intro to this example; what's its purpose? TR: REVISED, PLS REVIEW.--></para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt;
&lt;property name="driverClassName" value="${jdbc.driverClassName}"/&gt;
&lt;property name="url" value="${jdbc.url}"/&gt;
&lt;property name="username" value="${jdbc.username}"/&gt;
&lt;property name="password" value="${jdbc.password}"/&gt;
&lt;/bean&gt;
&lt;bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"&gt;
&lt;property name="configLocation" value="WEB-INF/sqlmap-config.xml"/&gt;
&lt;property name="dataSource" ref="dataSource"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
</section>
<section id="orm-ibatis-template">
<title>Using <classname>SqlMapClientTemplate</classname> and
<classname>SqlMapClientDaoSupport</classname></title>
<para>The <classname>SqlMapClientDaoSupport</classname> class offers a
supporting class similar to the <classname>SqlMapDaoSupport</classname>.
We extend it to implement our DAO:</para>
<programlisting language="java">public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {
public Account getAccount(String email) throws DataAccessException {
return (Account) getSqlMapClientTemplate().queryForObject("getAccountByEmail", email);
}
public void insertAccount(Account account) throws DataAccessException {
getSqlMapClientTemplate().update("insertAccount", account);
}
}</programlisting>
<para>In the DAO, we use the pre-configured
<classname>SqlMapClientTemplate</classname> to execute the queries,
after setting up the <literal>SqlMapAccountDao</literal> in the
application context and wiring it with our
<literal>SqlMapClient</literal> instance:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="accountDao" class="example.SqlMapAccountDao"&gt;
&lt;property name="sqlMapClient" ref="sqlMapClient"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>An <classname>SqlMapTemplate</classname> instance can also be
created manually, passing in the <literal>SqlMapClient</literal> as
constructor argument. The <literal>SqlMapClientDaoSupport</literal> base
class simply preinitializes a
<classname>SqlMapClientTemplate</classname> instance for us.</para>
<para>The <classname>SqlMapClientTemplate</classname> offers a generic
<literal>execute</literal> method, taking a custom
<literal>SqlMapClientCallback</literal> implementation as argument. This
can, for example, be used for batching:</para>
<programlisting language="java">public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {
public void insertAccount(Account account) throws DataAccessException {
getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
executor.startBatch();
executor.update("insertAccount", account);
executor.update("insertAddress", account.getAddress());
executor.executeBatch();
}
});
}
}</programlisting>
<para>In general, any combination of operations offered by the native
<literal>SqlMapExecutor</literal> API can be used in such a callback.
Any thrown <literal>SQLException</literal> is converted automatically to
Spring's generic <classname>DataAccessException</classname>
hierarchy.</para>
</section>
<section id="orm-ibatis-straight">
<title>Implementing DAOs based on plain iBATIS API</title>
<para>DAOs can also be written against plain iBATIS API, without any
Spring dependencies, directly using an injected
<literal>SqlMapClient</literal>. The following example shows a
corresponding DAO implementation:</para>
<programlisting language="java">public class SqlMapAccountDao implements AccountDao {
private SqlMapClient sqlMapClient;
public void setSqlMapClient(SqlMapClient sqlMapClient) {
this.sqlMapClient = sqlMapClient;
}
public Account getAccount(String email) {
try {
return (Account) this.sqlMapClient.queryForObject("getAccountByEmail", email);
}
catch (SQLException ex) {
throw new MyDaoException(ex);
}
}
public void insertAccount(Account account) throws DataAccessException {
try {
this.sqlMapClient.update("insertAccount", account);
}
catch (SQLException ex) {
throw new MyDaoException(ex);
}
}
}</programlisting>
<para>In this scenario, you need to handle the
<literal>SQLException</literal> thrown by the iBATIS API in a custom
fashion, usually by wrapping it in your own application-specific DAO
exception. Wiring in the application context would still look like it
does in the example for the
<classname>SqlMapClientDaoSupport</classname><!--Clarify what wiring the app context looks like. What do you mean *before*? Looks like *what* specifically? TR: REVISED, PLS REVIEW.-->,
due to the fact that the plain iBATIS-based DAO still follows the
dependency injection pattern:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="accountDao" class="example.SqlMapAccountDao"&gt;
&lt;property name="sqlMapClient" ref="sqlMapClient"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
</section>
</section>
</chapter>