You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2054 lines
102 KiB
2054 lines
102 KiB
<?xml version="1.0" encoding="UTF-8"?> |
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" |
|
"http://www.oasis-open.org/docbook/xml/4.5/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"><beans> |
|
|
|
<lineannotation><!-- <classname>Exception</classname> translation bean post processor --></lineannotation> |
|
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"/> |
|
|
|
</beans></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 3.0, Spring requires Hibernate 3.2 or later.</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"><beans> |
|
|
|
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> |
|
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/> |
|
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/> |
|
<property name="username" value="sa"/> |
|
<property name="password" value=""/> |
|
</bean> |
|
|
|
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> |
|
<property name="dataSource" ref="myDataSource"/> |
|
<property name="mappingResources"> |
|
<list> |
|
<value>product.hbm.xml</value> |
|
</list> |
|
</property> |
|
<property name="hibernateProperties"> |
|
<value> |
|
hibernate.dialect=org.hibernate.dialect.HSQLDialect |
|
</value> |
|
</property> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/> |
|
|
|
</beans></programlisting> |
|
|
|
<para>You can also access a JNDI-located |
|
<interfacename>SessionFactory</interfacename>, using Spring's |
|
<classname>JndiObjectFactoryBean</classname> / |
|
<literal><jee:jndi-lookup></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"><beans> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"> |
|
<property name="sessionFactory" ref="mySessionFactory"/> |
|
</bean> |
|
|
|
</beans></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"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns:aop="http://www.springframework.org/schema/aop" |
|
xmlns:tx="http://www.springframework.org/schema/tx" |
|
xsi:schemaLocation=" |
|
http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-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"> |
|
|
|
<lineannotation><!-- <interfacename>SessionFactory</interfacename>, <interfacename>DataSource</interfacename>, etc. omitted --></lineannotation> |
|
|
|
<bean id="transactionManager" |
|
class="org.springframework.orm.hibernate3.HibernateTransactionManager"> |
|
<property name="sessionFactory" ref="sessionFactory"/> |
|
</bean> |
|
|
|
<aop:config> |
|
<aop:pointcut id="productServiceMethods" |
|
expression="execution(* product.ProductService.*(..))"/> |
|
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> |
|
</aop:config> |
|
|
|
<tx:advice id="txAdvice" transaction-manager="myTxManager"> |
|
<tx:attributes> |
|
<tx:method name="increasePrice*" propagation="REQUIRED"/> |
|
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> |
|
<tx:method name="*" propagation="SUPPORTS" read-only="true"/> |
|
</tx:attributes> |
|
</tx:advice> |
|
|
|
<bean id="myProductService" class="product.SimpleProductService"> |
|
<property name="productDao" ref="myProductDao"/> |
|
</bean> |
|
|
|
</beans></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</lineannotation> |
|
<lineannotation>// 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<Product> 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 "<tx:annotation-driven/>" |
|
entry.<!--What does preceding example show, what's its relation to this example? TR: REVISED, PLS REVIEW.--></para> |
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns:aop="http://www.springframework.org/schema/aop" |
|
xmlns:tx="http://www.springframework.org/schema/tx" |
|
xsi:schemaLocation=" |
|
http://www.springframework.org/schema/beans |
|
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"> |
|
|
|
<lineannotation><!-- <interfacename>SessionFactory</interfacename>, <interfacename>DataSource</interfacename>, etc. omitted --></lineannotation> |
|
|
|
<bean id="transactionManager" |
|
class="org.springframework.orm.hibernate3.HibernateTransactionManager"> |
|
<property name="sessionFactory" ref="sessionFactory"/> |
|
</bean> |
|
|
|
<tx:annotation-driven/> |
|
|
|
<bean id="myProductService" class="product.SimpleProductService"> |
|
<property name="productDao" ref="myProductDao"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> |
|
<property name="sessionFactory" ref="mySessionFactory"/> |
|
</bean> |
|
|
|
<bean id="myProductService" class="product.ProductServiceImpl"> |
|
<property name="transactionManager" ref="myTxManager"/> |
|
<property name="productDao" ref="myProductDao"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<jee:jndi-lookup id="dataSource1" jndi-name="java:comp/env/jdbc/myds1"/> |
|
|
|
<jee:jndi-lookup id="dataSource2" jndi-name="java:comp/env/jdbc/myds2"/> |
|
|
|
<bean id="mySessionFactory1" |
|
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> |
|
<property name="dataSource" ref="myDataSource1"/> |
|
<property name="mappingResources"> |
|
<list> |
|
<value>product.hbm.xml</value> |
|
</list> |
|
</property> |
|
<property name="hibernateProperties"> |
|
<value> |
|
hibernate.dialect=org.hibernate.dialect.MySQLDialect |
|
hibernate.show_sql=true |
|
</value> |
|
</property> |
|
</bean> |
|
|
|
<bean id="mySessionFactory2" |
|
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> |
|
<property name="dataSource" ref="myDataSource2"/> |
|
<property name="mappingResources"> |
|
<list> |
|
<value>inventory.hbm.xml</value> |
|
</list> |
|
</property> |
|
<property name="hibernateProperties"> |
|
<value> |
|
hibernate.dialect=org.hibernate.dialect.OracleDialect |
|
</value> |
|
</property> |
|
</bean> |
|
|
|
<bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"> |
|
<property name="sessionFactory" ref="mySessionFactory1"/> |
|
</bean> |
|
|
|
<bean id="myInventoryDao" class="product.InventoryDaoImpl"> |
|
<property name="sessionFactory" ref="mySessionFactory2"/> |
|
</bean> |
|
|
|
<bean id="myProductService" class="product.ProductServiceImpl"> |
|
<property name="productDao" ref="myProductDao"/> |
|
<property name="inventoryDao" ref="myInventoryDao"/> |
|
</bean> |
|
|
|
<aop:config> |
|
<aop:pointcut id="productServiceMethods" |
|
expression="execution(* product.ProductService.*(..))"/> |
|
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> |
|
</aop:config> |
|
|
|
<tx:advice id="txAdvice" transaction-manager="myTxManager"> |
|
<tx:attributes> |
|
<tx:method name="increasePrice*" propagation="REQUIRED"/> |
|
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> |
|
<tx:method name="*" propagation="SUPPORTS" read-only="true"/> |
|
</tx:attributes> |
|
</tx:advice> |
|
|
|
</beans></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><jee:jndi-lookup></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>LocalSessionFactoryBean.</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"><beans> |
|
|
|
<bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"> |
|
<property name="configLocation" value="classpath:kodo.properties"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> |
|
<property name="driverClassName" value="${jdbc.driverClassName}"/> |
|
<property name="url" value="${jdbc.url}"/> |
|
<property name="username" value="${jdbc.username}"/> |
|
<property name="password" value="${jdbc.password}"/> |
|
</bean> |
|
|
|
<bean id="myPmf" class="org.datanucleus.jdo.JDOPersistenceManagerFactory" destroy-method="close"> |
|
<property name="connectionFactory" ref="dataSource"/> |
|
<property name="nontransactionalRead" value="true"/> |
|
</bean> |
|
|
|
</beans></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><jee:jndi-lookup></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"><beans> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"> |
|
<property name="persistenceManagerFactory" ref="myPmf"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<bean id="myPmfProxy" |
|
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"> |
|
<property name="targetPersistenceManagerFactory" ref="myPmf"/> |
|
</bean> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"> |
|
<property name="persistenceManagerFactory" ref="myPmfProxy"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<bean id="myPmfProxy" |
|
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"> |
|
<property name="targetPersistenceManagerFactory" ref="myPmf"/> |
|
<property name="allowCreate" value="false"/> |
|
</bean> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"> |
|
<property name="persistenceManagerFactory" ref="myPmfProxy"/> |
|
</bean> |
|
|
|
</beans></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"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans |
|
xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns:aop="http://www.springframework.org/schema/aop" |
|
xmlns:tx="http://www.springframework.org/schema/tx" |
|
xsi:schemaLocation=" |
|
http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-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"> |
|
|
|
<bean id="myTxManager" class="org.springframework.orm.jdo.JdoTransactionManager"> |
|
<property name="persistenceManagerFactory" ref="myPmf"/> |
|
</bean> |
|
|
|
<bean id="myProductService" class="product.ProductServiceImpl"> |
|
<property name="productDao" ref="myProductDao"/> |
|
</bean> |
|
|
|
<tx:advice id="txAdvice" transaction-manager="txManager"> |
|
<tx:attributes> |
|
<tx:method name="increasePrice*" propagation="REQUIRED"/> |
|
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> |
|
<tx:method name="*" propagation="SUPPORTS" read-only="true"/> |
|
</tx:attributes> |
|
</tx:advice> |
|
|
|
<aop:config> |
|
<aop:pointcut id="productServiceMethods" |
|
expression="execution(* product.ProductService.*(..))"/> |
|
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> |
|
</aop:config> |
|
|
|
</beans></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"><beans> |
|
|
|
<bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> |
|
<property name="persistenceUnitName" value="myPersistenceUnit"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> |
|
|
|
</beans></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 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"><beans> |
|
|
|
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> |
|
<property name="dataSource" ref="someDataSource"/> |
|
<property name="loadTimeWeaver"> |
|
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> |
|
</property> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
|
|
<para>The following example shows a typical |
|
<literal>persistence.xml</literal> file:</para> |
|
|
|
<programlisting language="xml"><persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> |
|
|
|
<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL"> |
|
<mapping-file>META-INF/orm.xml</mapping-file> |
|
<exclude-unlisted-classes/> |
|
</persistence-unit> |
|
|
|
</persistence></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><exclude-unlisted-classes/></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><exclude-unlisted-classes> false |
|
</exclude-unlisted-classes/></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>Refer to <xref linkend="aop-aj-ltw-spring" /> in the AOP chapter for more insight regarding the |
|
<interfacename>LoadTimeWeaver</interfacename> implementations and their setup, either generic or customized to |
|
various platforms (such as Tomcat, WebLogic, OC4J, GlassFish, Resin and JBoss).</para> |
|
|
|
|
|
<para>As described in the aforementioned section, you can configure a context-wide <interfacename>LoadTimeWeaver</interfacename> |
|
using the <literal>context:load-time-weaver</literal> configuration element. (This has been available since Spring 2.5.) |
|
Such a global weaver is picked up by all JPA <classname>LocalContainerEntityManagerFactoryBeans</classname> |
|
automatically. This is the preferred way of setting up a load-time weaver, delivering autodetection of the platform |
|
(WebLogic, OC4J, GlassFish, Tomcat, Resin, JBoss or VM agent) and automatic propagation of the weaver to all weaver-aware beans:</para> |
|
|
|
<programlisting language="xml"><context:load-time-weaver/> |
|
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> |
|
... |
|
</bean></programlisting> |
|
|
|
<para> However, if needed, one can manually specify a dedicated weaver through the <literal>loadTimeWeaver</literal> property:</para> |
|
|
|
<programlisting language="xml"><bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> |
|
<property name="loadTimeWeaver"> |
|
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/> |
|
</property> |
|
</bean></programlisting> |
|
|
|
<para>No matter how the LTW is configured, using this technique, JPA applications relying on |
|
instrumentation can run in the target platform (ex: Tomcat) without needing an agent. |
|
This is important especially when the hosting applications 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-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"><bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"> |
|
<property name="persistenceXmlLocations"> |
|
<list> |
|
<value>org/springframework/orm/jpa/domain/persistence-multi.xml</value> |
|
<value>classpath:/my/package/**/custom-persistence.xml</value> |
|
<value>classpath*:META-INF/persistence.xml</value> |
|
</list> |
|
</property> |
|
<property name="dataSources"> |
|
<map> |
|
<entry key="localDataSource" value-ref="local-db"/> |
|
<entry key="remoteDataSource" value-ref="remote-db"/> |
|
</map> |
|
</property> |
|
<lineannotation><!-- if no datasource is specified, use this one --></lineannotation> |
|
<property name="defaultDataSource" ref="remoteDataSource"/> |
|
</bean> |
|
|
|
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> |
|
<property name="persistenceUnitManager" ref="pum"/> |
|
<property name="persistenceUnitName" value="myCustomUnit"/> |
|
</bean></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"><beans> |
|
|
|
<lineannotation><!-- bean post-processor for JPA annotations --></lineannotation> |
|
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"/> |
|
|
|
</beans></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"><beans> |
|
|
|
<lineannotation><!-- post-processors for all standard config annotations --></lineannotation> |
|
<context:annotation-config/> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"/> |
|
|
|
</beans></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"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns:aop="http://www.springframework.org/schema/aop" |
|
xmlns:tx="http://www.springframework.org/schema/tx" |
|
xsi:schemaLocation=" |
|
http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-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"> |
|
|
|
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager"> |
|
<property name="entityManagerFactory" ref="myEmf"/> |
|
</bean> |
|
|
|
<bean id="myProductService" class="product.ProductServiceImpl"> |
|
<property name="productDao" ref="myProductDao"/> |
|
</bean> |
|
|
|
<aop:config> |
|
<aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/> |
|
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> |
|
</aop:config> |
|
|
|
<tx:advice id="txAdvice" transaction-manager="myTxManager"> |
|
<tx:attributes> |
|
<tx:method name="increasePrice*" propagation="REQUIRED"/> |
|
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> |
|
<tx:method name="*" propagation="SUPPORTS" read-only="true"/> |
|
</tx:attributes> |
|
</tx:advice> |
|
|
|
</beans></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"><sqlMap namespace="Account"> |
|
|
|
<resultMap id="result" class="examples.Account"> |
|
<result property="name" column="NAME" columnIndex="1"/> |
|
<result property="email" column="EMAIL" columnIndex="2"/> |
|
</resultMap> |
|
|
|
<select id="getAccountByEmail" resultMap="result"> |
|
select ACCOUNT.NAME, ACCOUNT.EMAIL |
|
from ACCOUNT |
|
where ACCOUNT.EMAIL = #value# |
|
</select> |
|
|
|
<insert id="insertAccount"> |
|
insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#) |
|
</insert> |
|
|
|
</sqlMap></programlisting> |
|
|
|
<para>The configuration file for iBATIS 2 looks like this:</para> |
|
|
|
<programlisting language="xml"><sqlMapConfig> |
|
|
|
<sqlMap resource="example/Account.xml"/> |
|
|
|
</sqlMapConfig></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"><beans> |
|
|
|
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> |
|
<property name="driverClassName" value="${jdbc.driverClassName}"/> |
|
<property name="url" value="${jdbc.url}"/> |
|
<property name="username" value="${jdbc.username}"/> |
|
<property name="password" value="${jdbc.password}"/> |
|
</bean> |
|
|
|
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> |
|
<property name="configLocation" value="WEB-INF/sqlmap-config.xml"/> |
|
<property name="dataSource" ref="dataSource"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<bean id="accountDao" class="example.SqlMapAccountDao"> |
|
<property name="sqlMapClient" ref="sqlMapClient"/> |
|
</bean> |
|
|
|
</beans></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"><beans> |
|
|
|
<bean id="accountDao" class="example.SqlMapAccountDao"> |
|
<property name="sqlMapClient" ref="sqlMapClient"/> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
</section> |
|
</section> |
|
</chapter>
|
|
|