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.
2082 lines
99 KiB
2082 lines
99 KiB
<?xml version="1.0" encoding="UTF-8"?> |
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
|
<chapter id="orm"> |
|
<title>Object Relational Mapping (ORM) data access</title> |
|
|
|
<section id="orm-introduction"> |
|
<title>Introduction</title> |
|
|
|
<para>The Spring Framework provides integration with <emphasis>Hibernate, |
|
JPA, JDO <emphasis>and</emphasis> iBATIS SQL Maps</emphasis>: in terms of |
|
resource management, DAO implementation support, and transaction |
|
strategies. For example for Hibernate, there is first-class support with |
|
lots of IoC convenience features, addressing many typical Hibernate |
|
integration issues. All of these support packages for O/R (Object |
|
Relational) mappers can be configured through Dependency Injection, can |
|
participate in Spring's resource and transaction management and they |
|
comply with Spring's generic transaction and DAO exception hierarchies. |
|
The curently recommended integration style is to code DAOs against plain |
|
Hibernate/JPA/JDO/etc APIs. The older style of using Spring's DAO |
|
'templates' is no longer recommended and the coverage of this style can be |
|
found in the <xref linkend="classic-spring-orm" /> Appendix.</para> |
|
|
|
<para>Spring adds significant support when using the O/R mapping layer of |
|
your choice to create data access applications. First of all, you should |
|
know that once you started using Spring's support for O/R mapping, you |
|
don't have to go all the way. No matter to what extent, you're invited to |
|
review and leverage the Spring approach, before deciding to take the |
|
effort and risk of building a similar infrastructure in-house. Much of the |
|
O/R mapping support, no matter what technology you're using may be used in |
|
a library style, as everything is designed as a set of reusable JavaBeans. |
|
Usage inside a Spring IoC container does provide additional benefits in |
|
terms of ease of configuration and deployment; as such, most examples in |
|
this section show configuration inside a Spring container.</para> |
|
|
|
<para>Some of the benefits of using the Spring Framework to create your |
|
ORM DAOs include:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><emphasis>Ease of testing.</emphasis> Spring's IoC approach |
|
makes it easy to swap the implementations and config locations of |
|
Hibernate <interfacename>SessionFactory</interfacename> instances, |
|
JDBC <interfacename>DataSource</interfacename> instances, transaction |
|
managers, and mappes object implementations (if needed). This makes it |
|
much easier to isolate and test each piece of persistence-related code |
|
in isolation.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis>Common data access exceptions.</emphasis> Spring can |
|
wrap exceptions from your O/R mapping tool of choice, converting them |
|
from proprietary (potentially checked) exceptions to a common runtime |
|
DataAccessException hierarchy. This 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 |
|
anywhere you need to. 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, |
|
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 |
|
using Hibernate generally needs to use the same Hibernate |
|
<interfacename>Session</interfacename> for efficiency and proper |
|
transaction handling. Spring makes it easy to transparently create and |
|
bind a <interfacename>Session</interfacename> to the current thread, |
|
either by using an explicit 'template' wrapper class at the Java code |
|
level or by exposing a current <interfacename>Session</interfacename> |
|
through the Hibernate <interfacename>SessionFactory</interfacename> |
|
(for DAOs based on plain Hibernate API). Thus Spring solves many of |
|
the issues that repeatedly arise from typical Hibernate usage, for any |
|
transaction environment (local or JTA).</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis>Integrated transaction management.</emphasis> Spring |
|
allows you to wrap your O/R mapping code with either a declarative, |
|
AOP style method interceptor, or an explicit 'template' wrapper class |
|
at the Java code level. In either case, transaction semantics are |
|
handled for you, and proper transaction handling (rollback, etc) in |
|
case of exceptions is taken care of. As discussed below, you also get |
|
the benefit of being able to use and swap various transaction |
|
managers, without your Hibernate/JDO related code being affected: for |
|
example, between local transactions and JTA, with the same full |
|
services (such as declarative transactions) available in both |
|
scenarios. As an additional benefit, JDBC-related code can fully |
|
integrate transactionally with the code you use to do O/R mapping. |
|
This is useful for data access that's not suitable for O/R mapping, |
|
such as batch processing or streaming of BLOBs, which still needs 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 can therefore serve as working sample app |
|
that illustrates the use of Hibernate and JPA in a Spring web application. |
|
It also leverages declarative transaction demarcation with different |
|
transaction strategies.</para> |
|
|
|
<para>Beyond the samples shipped with Spring, there are a variety of |
|
Spring-based O/R mapping samples provided by specific vendors.</para> |
|
</section> |
|
|
|
<section id="orm-general"> |
|
<title>General ORM integration considerations</title> |
|
|
|
<para>This section highlights some common considerations regardles of |
|
which ORM technology you use. The Hibernate section provides more details |
|
and also show these features/configurations in a concrete context.</para> |
|
|
|
<para>The major goal is to allow for clear application layering, with any |
|
data access and transaction technology, and for loose coupling of |
|
application objects. No more business service dependencies on the data |
|
access or transaction strategy, no more hard-coded resource lookups, no |
|
more hard-to-replace singletons, no more custom service registries. One |
|
simple and consistent approach to wiring up application objects, keeping |
|
them as reusable and free from container dependencies as possible. All the |
|
individual data access features are usable on their own but integrate |
|
nicely with Spring's application context concept, providing XML-based |
|
configuration and cross-referencing of plain JavaBean instances that don't |
|
need to be Spring-aware. In a typical Spring application, many important |
|
objects are JavaBeans: data access templates, data access objects, |
|
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 often cluttered with repetitive |
|
resource management code. Many projects try to invent their own |
|
solutions for this issue, sometimes sacrificing proper handling of |
|
failures for programming convenience. Spring advocates strikingly simple |
|
solutions for proper resource handling, namely IoC via templating in the |
|
case of JDBC and applying AOP interceptors for the ORM technologies. |
|
</para> |
|
|
|
<para>The infrastructure cares for proper resource handling, and for |
|
appropriate conversion of specific API exceptions to an unchecked |
|
infrastructure exception hierarchy. Spring introduces a DAO exception |
|
hierarchy, applicable to any data access strategy. For direct JDBC, the |
|
<classname>JdbcTemplate</classname> class mentioned in a previous |
|
section cares for connection handling, and for 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, via |
|
respective Spring transaction managers. For the supported ORM |
|
technologies Spring offers Hibernate, JPA and JDO support via the |
|
Hibernate / JPA / JDO transaction managers as well as JTA support. For |
|
more details on the transaction support see the <xref |
|
linkend="transaction" /> chapter. </para> |
|
</section> |
|
|
|
<section id="orm-exception-translation"> |
|
<title>Exception Translation</title> |
|
|
|
<para>Using Hibernate, JDO or JPA in a DAO means that you will have to |
|
decide how to handle the persistence technology's native exception |
|
classes. The DAO could potentially throw a subclass of a |
|
<classname>HibernateException</classname>, |
|
<classname>JDOException</classname> or |
|
<classname>PersistenceException</classname> depending on the technology |
|
in use. These exceptions are all run-time exceptions and does not have |
|
to be declared or caught. You would potentially 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 tradeoff |
|
might be acceptable to applications that are strongly ORM-based and/or |
|
do not need any special exception treatment. However, Spring offers a |
|
solution allowing 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 will automatically look for all exception |
|
translators (implementations of the |
|
<interfacename>PersistenceExceptionTranslator</interfacename> interface) |
|
and advise 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: DAOs can be implemented based on the plain persistence |
|
technology's API and annotations, while still being able to benefit 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><emphasis>Note: As of Spring 2.5, Spring requires Hibernate 3.1 or |
|
higher. Neither Hibernate 2.1 nor Hibernate 3.0 are supported |
|
anymore.</emphasis></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, |
|
Spring allows you to 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 just |
|
receive references to such pre-defined instances via bean references |
|
(the DAO definition in the next section illustrates this). The following |
|
excerpt from an XML application context definition shows how to set up a |
|
JDBC <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>Note that 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> |
|
|
|
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> |
|
<property name="jndiName" value="java:comp/env/jdbc/myds"/> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
|
|
<para>You can also access a JNDI-located |
|
<interfacename>SessionFactory</interfacename>, using Spring's |
|
<classname>JndiObjectFactoryBean</classname> 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 provides a feature called "contextual Sessions", where |
|
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 looks like as follows, 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 very similar to what you will find in 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 like 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, it |
|
would look as follows:</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 tieing the caller to |
|
the implementation strategy. This tradeoff might be acceptable to |
|
applications that are strongly Hibernate-based and/or do not need any |
|
special exception treatment.</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: returning the current |
|
<interfacename>Session</interfacename> associated with the ongoing JTA |
|
transaction, if any (no matter whether driven by Spring's |
|
<classname>JtaTransactionManager</classname>, by EJB CMT, or by |
|
JTA).</para> |
|
|
|
<para>In summary: DAOs can be implemented based on the plain Hibernate 3 |
|
API, while still being able to participate in Spring-managed |
|
transactions.</para> |
|
</section> |
|
|
|
<section id="orm-hibernate-tx-programmatic"> |
|
<title>Programmatic transaction demarcation</title> |
|
|
|
<para>Transactions can be demarcated in a higher level of the |
|
application, on top of such lower-level data access services spanning |
|
any number of operations. There are no restrictions on the |
|
implementation of the surrounding business service here as well, it just |
|
needs a Spring <classname>PlatformTransactionManager</classname>. Again, |
|
the latter can come from anywhere, but preferably as bean reference via |
|
a <methodname>setTransactionManager(..)</methodname> method - just like |
|
the <classname>productDAO</classname> should be set via 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> |
|
</section> |
|
|
|
<section id="orm-hibernate-tx-declarative"> |
|
<title>Declarative transaction demarcation</title> |
|
|
|
<para>Alternatively, one can use Spring's declarative transaction |
|
support, which essentially enables you to replace explicit transaction |
|
demarcation API calls in your Java code with an AOP transaction |
|
interceptor configured in a Spring container. This allows you to keep |
|
business services free of repetitive transaction demarcation code, and |
|
allows you to focus on adding business logic which is where the real |
|
value of your application lies. Furthermore, transaction semantics like |
|
propagation behavior and isolation level can be changed in a |
|
configuration file and do not affect the business service |
|
implementations.</para> |
|
|
|
<programlisting language="xml"><beans> |
|
|
|
<bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> |
|
<property name="sessionFactory" ref="mySessionFactory"/> |
|
</bean> |
|
|
|
<bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean"> |
|
<property name="proxyInterfaces" value="product.ProductService"/> |
|
<property name="target"> |
|
<bean class="product.DefaultProductService"> |
|
<property name="productDao" ref="myProductDao"/> |
|
</bean> |
|
</property> |
|
<property name="interceptorNames"> |
|
<list> |
|
<value>myTxInterceptor</value> <lineannotation><!-- the transaction interceptor (configured elsewhere) --></lineannotation> |
|
</list> |
|
</property> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
|
|
<programlisting language="java">public class ProductServiceImpl implements ProductService { |
|
|
|
private ProductDao productDao; |
|
|
|
public void setProductDao(ProductDao productDao) { |
|
this.productDao = productDao; |
|
} |
|
|
|
<lineannotation>// notice the absence of transaction demarcation code in this method</lineannotation> |
|
<lineannotation>// Spring's declarative transaction infrastructure will be demarcating transactions on your behalf </lineannotation> |
|
public void increasePriceOfAllProductsInCategory(final String category) { |
|
List productsToChange = this.productDao.loadProductsByCategory(category); |
|
<lineannotation>// ...</lineannotation> |
|
} |
|
}</programlisting> |
|
|
|
<para>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> will trigger a rollback in |
|
case of an unchecked application exception, or if the transaction has |
|
been 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> |
|
|
|
<para>The following higher level approach to declarative transactions |
|
doesn't use the <classname>ProxyFactoryBean</classname>, and as such may |
|
be easier to use if you have a large number of service objects that you |
|
wish to make transactional.</para> |
|
|
|
<note> |
|
<para>You are <emphasis>strongly</emphasis> encouraged to read the |
|
section entitled <xref linkend="transaction-declarative" /> if you |
|
have not done so already prior to continuing.</para> |
|
</note> |
|
|
|
<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-2.5.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> |
|
|
|
<lineannotation><!-- <interfacename>SessionFactory</interfacename>, <interfacename>DataSource</interfacename>, etc. omitted --></lineannotation> |
|
|
|
<bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> |
|
<property name="sessionFactory" ref="mySessionFactory"/> |
|
</bean> |
|
|
|
<aop:config> |
|
<aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/> |
|
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> |
|
</aop:config> |
|
|
|
<tx:advice id="txAdvice" transaction-manager="myTxManager"> |
|
<tx:attributes> |
|
<tx:method name="increasePrice*" propagation="REQUIRED"/> |
|
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> |
|
<tx:method name="*" propagation="SUPPORTS" read-only="true"/> |
|
</tx:attributes> |
|
</tx:advice> |
|
|
|
<bean id="myProductService" class="product.SimpleProductService"> |
|
<property name="productDao" ref="myProductDao"/> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
</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 could even |
|
use a custom <classname>PlatformTransactionManager</classname> |
|
implementation. So switching from native Hibernate transaction |
|
management to JTA, such as when facing distributed transaction |
|
requirements for certain deployments of your application, is just a |
|
matter of configuration. Simply replace the Hibernate transaction |
|
manager with Spring's JTA transaction implementation. Both transaction |
|
demarcation and data access code will work without changes, as they just |
|
use the generic transaction management APIs.</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 of your |
|
DAOs 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> |
|
|
|
<bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean"> |
|
<property name="jndiName value="java:comp/env/jdbc/myds1"/> |
|
</bean> |
|
|
|
<bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean"> |
|
<property name="jndiName" value="java:comp/env/jdbc/myds2"/> |
|
</bean> |
|
|
|
<bean id="mySessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> |
|
<property name="dataSource" ref="myDataSource1"/> |
|
<property name="mappingResources"> |
|
<list> |
|
<value>product.hbm.xml</value> |
|
</list> |
|
</property> |
|
<property name="hibernateProperties"> |
|
<value> |
|
hibernate.dialect=org.hibernate.dialect.MySQLDialect |
|
hibernate.show_sql=true |
|
</value> |
|
</property> |
|
</bean> |
|
|
|
<bean id="mySessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> |
|
<property name="dataSource" ref="myDataSource2"/> |
|
<property name="mappingResources"> |
|
<list> |
|
<value>inventory.hbm.xml</value> |
|
</list> |
|
</property> |
|
<property name="hibernateProperties"> |
|
<value> |
|
hibernate.dialect=org.hibernate.dialect.OracleDialect |
|
</value> |
|
</property> |
|
</bean> |
|
|
|
<bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> |
|
|
|
<bean id="myProductDao" class="product.ProductDaoImpl"> |
|
<property name="sessionFactory" ref="mySessionFactory1"/> |
|
</bean> |
|
|
|
<bean id="myInventoryDao" class="product.InventoryDaoImpl"> |
|
<property name="sessionFactory" ref="mySessionFactory2"/> |
|
</bean> |
|
|
|
<lineannotation><!-- this shows the Spring 1.x style of declarative transaction configuration --></lineannotation> |
|
<lineannotation><!-- it is totally supported, 100% legal in Spring 2.x, but see also above for the sleeker, Spring 2.0 style --></lineannotation> |
|
<bean id="myProductService" |
|
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> |
|
<property name="transactionManager" ref="myTxManager"/> |
|
<property name="target"> |
|
<bean class="product.ProductServiceImpl"> |
|
<property name="productDao" ref="myProductDao"/> |
|
<property name="inventoryDao" ref="myInventoryDao"/> |
|
</bean> |
|
</property> |
|
<property name="transactionAttributes"> |
|
<props> |
|
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop> |
|
<prop key="someOtherBusinessMethod">PROPAGATION_REQUIRES_NEW</prop> |
|
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> |
|
</props> |
|
</property> |
|
</bean> |
|
|
|
</beans></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 JCA connector (as long as not using EJB to initiate |
|
transactions).</para> |
|
|
|
<para><classname>HibernateTransactionManager</classname> can export the |
|
JDBC <interfacename>Connection</interfacename> used by Hibernate to |
|
plain JDBC access code, for a specific |
|
<interfacename>DataSource</interfacename>. This allows for high-level |
|
transaction demarcation with mixed Hibernate/JDBC data access completely |
|
without JTA, as long as you are just accessing one database! |
|
<classname>HibernateTransactionManager</classname> will automatically |
|
expose the Hibernate transaction as JDBC transaction if the passed-in |
|
<interfacename>SessionFactory</interfacename> has been set up with a |
|
<interfacename>DataSource</interfacename> (through the "dataSource" |
|
property of the <classname>LocalSessionFactoryBean</classname> class). |
|
Alternatively, the <interfacename>DataSource</interfacename> that the |
|
transactions are supposed to be exposed for can also be specified |
|
explicitly, through the "dataSource" property of the |
|
<classname>HibernateTransactionManager</classname> class.</para> |
|
</section> |
|
|
|
<section id="orm-hibernate-resources"> |
|
<title>Container resources versus local resources</title> |
|
|
|
<para>Spring's resource management allows for simple switching between a |
|
JNDI <interfacename>SessionFactory</interfacename> and a local one, |
|
without having to change a single line of application code. The decision |
|
as to whether to keep the resource definitions in the container or |
|
locally within the application, is mainly a matter of the transaction |
|
strategy being used. Compared to a Spring-defined local |
|
<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 J2EE server's management infrastructure, but does |
|
not add actual value beyond that.</para> |
|
|
|
<para>An important benefit of Spring's transaction support is that it |
|
isn't bound to a container at all. Configured to any other strategy than |
|
JTA, it will work in a standalone or test environment too. Especially |
|
for the typical case of single-database transactions, this is a very |
|
lightweight and powerful alternative to JTA. When using local EJB |
|
Stateless Session Beans to drive transactions, you depend both on an EJB |
|
container and JTA - even if you just access a single database anyway, |
|
and just use SLSBs for declarative transactions via CMT. The alternative |
|
of using JTA programmatically requires a J2EE environment as well. JTA |
|
does not just involve container dependencies in terms of JTA itself and |
|
of JNDI <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> being configured |
|
for proper JVM-level caching.</para> |
|
|
|
<para>Spring-driven transactions can work with a locally defined |
|
Hibernate <interfacename>SessionFactory</interfacename> nicely, just |
|
like with a local JDBC <interfacename>DataSource</interfacename> - if |
|
accessing a single database, of course. Therefore you just have to fall |
|
back to Spring's JTA transaction strategy when actually facing |
|
distributed transaction requirements. Note that a JCA connector needs |
|
container-specific deployment steps, and obviously JCA support in the |
|
first place. This is far more hassle than deploying a simple web app |
|
with local resource definitions and Spring-driven transactions. And you |
|
often need the Enterprise Edition of your container, as for example |
|
WebLogic Express does not provide JCA. A Spring application with local |
|
resources and transactions spanning one single database will work in any |
|
J2EE web container (without JTA, JCA, or EJB) - like Tomcat, Resin, or |
|
even plain Jetty. Additionally, such a middle tier can be reused in |
|
desktop applications or test suites easily.</para> |
|
|
|
<para>All things considered: if you do not use EJB, stick with local |
|
<interfacename>SessionFactory</interfacename> setup and Spring's |
|
<classname>HibernateTransactionManager</classname> or |
|
<classname>JtaTransactionManager</classname>. You will get all of the |
|
benefits including proper transactional JVM-level caching and |
|
distributed transactions, without any container deployment hassle. JNDI |
|
registration of a Hibernate |
|
<interfacename>SessionFactory</interfacename> via the JCA connector |
|
really only adds value when used in conjunction with EJBs.</para> |
|
</section> |
|
|
|
<section id="orm-hibernate-invalid-jdbc-access-error"> |
|
<title>Spurious application server warnings when using Hibernate</title> |
|
|
|
<para>In some JTA environments with very strict |
|
<interfacename>XADataSource</interfacename> implementations -- currently |
|
only some WebLogic and WebSphere versions -- when using Hibernate |
|
configured without any awareness of 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 will |
|
say something to the effect that the connection being accessed is no |
|
longer valid, or JDBC access is no longer valid, possibly because the |
|
transaction is no longer active. As an example, here is an actual |
|
exception from WebLogic:</para> |
|
|
|
<programlisting>java.sql.SQLException: The transaction is no longer active - status: 'Committed'. |
|
No further JDBC access is allowed within this transaction.</programlisting> |
|
|
|
<para>This warning is easy to resolve by simply making Hibernate aware |
|
of the JTA <interfacename>PlatformTransactionManager</interfacename> |
|
instance, to which it will also synchronize (along with Spring). This |
|
may be done in two ways:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>If in your application context you are already directly |
|
obtaining the JTA |
|
<interfacename>PlatformTransactionManager</interfacename> object |
|
(presumably from JNDI via <literal>JndiObjectFactoryBean</literal>) |
|
and feeding it for example to Spring's |
|
<classname>JtaTransactionManager</classname>, then the easiest way |
|
is to simply specify a reference to this as the value of |
|
<classname>LocalSessionFactoryBean</classname>'s |
|
<emphasis>jtaTransactionManager</emphasis> property. Spring will |
|
then make the object available to Hibernate.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>More likely you do not already have the JTA |
|
<interfacename>PlatformTransactionManager</interfacename> instance |
|
(since Spring's <classname>JtaTransactionManager</classname> can |
|
find it itself) so you need to instead configure Hibernate to also |
|
look it up directly. This is done by configuring an AppServer |
|
specific <literal>TransactionManagerLookup</literal> class in the |
|
Hibernate configuration, as described in the Hibernate |
|
manual.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>It is not necessary to read any more for proper usage, but the |
|
full sequence of events with and without Hibernate being aware of the |
|
JTA <interfacename>PlatformTransactionManager</interfacename> will now |
|
be described.</para> |
|
|
|
<para>When Hibernate is not configured with any awareness of the JTA |
|
<interfacename>PlatformTransactionManager</interfacename>, the sequence |
|
of events when a JTA transaction commits is as follows:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>JTA transaction commits</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Spring's <classname>JtaTransactionManager</classname> is |
|
synchronized to the JTA transaction, so it is called back via an |
|
<emphasis>afterCompletion</emphasis> callback by the JTA transaction |
|
manager.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Among other activities, this can trigger a callback by Spring |
|
to Hibernate, via Hibernate's |
|
<literal>afterTransactionCompletion</literal> callback (used to |
|
clear the Hibernate cache), followed by an explicit |
|
<literal>close()</literal> call on the Hibernate Session, which |
|
results in Hibernate trying 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, since the |
|
transaction has already been committed.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>When Hibernate is configured with awareness of the JTA |
|
<interfacename>PlatformTransactionManager</interfacename>, the sequence |
|
of events when a JTA transaction commits is instead as follows:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>JTA transaction is ready to commit</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Spring's <classname>JtaTransactionManager</classname> is |
|
synchronized to the JTA transaction, so it is called back via 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>JTA Transaction commits</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Hibernate is synchronized to the JTA transaction, so it is |
|
called back via an <emphasis>afterCompletion</emphasis> callback by |
|
the JTA transaction manager, and can properly clear its |
|
cache.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
</section> |
|
|
|
<section id="orm-jdo"> |
|
<title>JDO</title> |
|
|
|
<para>Spring supports the standard JDO 2.0/2.1 API 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 for defining 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, a |
|
<interfacename>PersistenceManagerFactory</interfacename> can also be set |
|
up through direct instantiation of a |
|
<interfacename>PersistenceManagerFactory</interfacename> implementation |
|
class. A JDO <interfacename>PersistenceManagerFactory</interfacename> |
|
implementation class is supposed to follow the JavaBeans pattern, just |
|
like a JDBC <interfacename>DataSource</interfacename> implementation |
|
class, which is a natural fit for a Spring bean definition. This setup |
|
style usually supports a Spring-defined JDBC |
|
<interfacename>DataSource</interfacename>, passed into the |
|
"connectionFactory" property. For example, for the open source JDO |
|
implementation DataNucleus (formerly JPOX) (<ulink |
|
url="http://www.datanucleus.org/">http://www.datanucleus.org/</ulink>):</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>A JDO <interfacename>PersistenceManagerFactory</interfacename> can |
|
also be set up in the JNDI environment of a J2EE application server, |
|
usually through the JCA connector provided by the particular JDO |
|
implementation. Spring's standard |
|
<literal>JndiObjectFactoryBean</literal> can be used to retrieve and |
|
expose such a <interfacename>PersistenceManagerFactory</interfacename>. |
|
However, outside an EJB context, there is often no compelling benefit in |
|
holding the <interfacename>PersistenceManagerFactory</interfacename> in |
|
JNDI: only choose such setup for a good reason. See "container resources |
|
versus local resources" in the Hibernate section 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 against plain JDO API, without any Spring |
|
dependencies, directly using an injected |
|
<interfacename>PersistenceManagerFactory</interfacename>. A |
|
corresponding DAO implementation looks like as follows:</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>As the above DAO still follows the Dependency Injection pattern, |
|
it still fits nicely into a Spring container, just like 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 issue with such DAOs is that they always get a new |
|
<interfacename>PersistenceManager</interfacename> from the factory. To |
|
still access a Spring-managed transactional |
|
<interfacename>PersistenceManager</interfacename>, consider defining a |
|
<classname>TransactionAwarePersistenceManagerFactoryProxy</classname> |
|
(as included in Spring) in front of your target |
|
<interfacename>PersistenceManagerFactory</interfacename>, passing the |
|
proxy into your DAOs.</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 then 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 will first check for a current transactional |
|
<interfacename>PersistenceManager</interfacename> before getting a new |
|
one from the factory. <methodname>close()</methodname> calls on the |
|
<interfacename>PersistenceManager</interfacename> will be ignored in |
|
case of a transactional |
|
<interfacename>PersistenceManager</interfacename>.</para> |
|
|
|
<para>If your data access code will always run 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 prefer 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 |
|
to enforce active transactions through turning |
|
<classname>TransactionAwarePersistenceManagerFactoryProxy</classname>'s |
|
"allowCreate" flag off:</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 generally fatal - unless they 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 tradeoff might be acceptable to |
|
applications that are strongly JDO-based and/or do not need any special |
|
exception treatment.</para> |
|
|
|
<para>In summary: DAOs can be implemented based on plain JDO API, while |
|
still being able to participate in Spring-managed transactions. This |
|
might in particular appeal to people already familiar with JDO, feeling |
|
more natural to them. However, such DAOs will throw plain |
|
<exceptionname>JDOException</exceptionname>; conversion to Spring's |
|
<exceptionname>DataAccessException</exceptionname> would have to happen |
|
explicitly (if desired).</para> |
|
</section> |
|
|
|
<section id="orm-jdo-tx"> |
|
<title>Transaction management</title> |
|
|
|
<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-2.5.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> |
|
|
|
<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>Note that JDO requires an active transaction when modifying a |
|
persistent object. There is no concept like a non-transactional flush in |
|
JDO, in contrast to Hibernate. For this reason, the chosen JDO |
|
implementation needs to be set up for a specific environment: in |
|
particular, it needs to be explicitly set up 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 for |
|
participating in JTA transactions (whether driven by Spring's |
|
<classname>JtaTransactionManager</classname> or by EJB CMT / 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>interfacename</classname> support a custom |
|
<interfacename>JdoDialect</interfacename>, to be passed into the |
|
"jdoDialect" bean property. In such a scenario, the DAOs won't receive a |
|
<interfacename>PersistenceManagerFactory</interfacename> reference but |
|
rather a full <classname>JdoTemplate</classname> instance instead (for |
|
example, passed into <classname>JdoDaoSupport</classname>'s |
|
"jdoTemplate" property). A <interfacename>JdoDialect</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>applying query timeouts (automatically calculated from |
|
Spring-managed transaction timeout)</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 they are used within Spring's JDO |
|
support.</para> |
|
</section> |
|
</section> |
|
|
|
<section id="orm-jpa"> |
|
<title>JPA</title> |
|
|
|
<para>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>JPA setup in a Spring environment</title> |
|
|
|
<para>Spring JPA offers three ways of setting up JPA |
|
<interfacename>EntityManagerFactory</interfacename>:</para> |
|
|
|
<section id="orm-jpa-setup-lemfb"> |
|
<title><classname>LocalEntityManagerFactoryBean</classname></title> |
|
|
|
<para>The <classname>LocalEntityManagerFactoryBean</classname> creates |
|
an <interfacename>EntityManagerFactory</interfacename> suitable for |
|
environments which solely use JPA for data access. The factory bean |
|
will use the JPA <interfacename>PersistenceProvider</interfacename> |
|
autodetection mechanism (according to JPA's Java SE bootstrapping) |
|
and, in most cases, requires only the persistence unit name to be |
|
specified:</para> |
|
|
|
<programlisting language="xml"><beans> |
|
|
|
<bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> |
|
<property name="persistenceUnitName" value="myPersistenceUnit"/> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
|
|
<para>This is the simplest but also most limited form of JPA |
|
deployment. There is no way to link to an existing JDBC |
|
<interfacename>DataSource</interfacename> and no support for global |
|
transactions, for example. Furthermore, weaving (byte-code |
|
transformation) of persistent classes is provider-specific, often |
|
requiring a specific JVM agent to specified on startup. All in all, |
|
this option is only really sufficient for standalone applications and |
|
test environments (which is exactly what the JPA specification |
|
designed it for).</para> |
|
|
|
<para><emphasis>Only use this option in simple deployment environments |
|
like standalone applications and integration tests.</emphasis></para> |
|
</section> |
|
|
|
<section id="orm-jpa-setup-jndi"> |
|
<title><classname>Obtaining an EntityManagerFactory from |
|
JNDI</classname></title> |
|
|
|
<para>Obtaining an <interfacename>EntityManagerFactory</interfacename> |
|
from JNDI (for example in a Java EE 5 environment), is just 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 assumes standard Java EE 5 bootstrapping, with the Java EE |
|
server autodetecting persistence units (i.e. |
|
<literal>META-INF/persistence.xml</literal> files in application jars) |
|
and <literal>persistence-unit-ref</literal> entries in the Java EE |
|
deployment descriptor (e.g. <literal>web.xml</literal>) defining |
|
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 via dependency injection, and managing |
|
transactions for it (typically through |
|
<classname>JtaTransactionManager</classname>).</para> |
|
|
|
<para>Note that, in case of multiple persistence units used in the |
|
same application, the bean names of such a JNDI-retrieved persistence |
|
units should match the persistence unit names that the application |
|
uses to refer to them (e.g. in <literal>@PersistenceUnit</literal> and |
|
<literal>@PersistenceContext</literal> annotations).</para> |
|
|
|
<para><emphasis>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. </emphasis></para> |
|
</section> |
|
|
|
<section id="orm-jpa-setup-lcemfb"> |
|
<title><classname>LocalContainerEntityManagerFactoryBean</classname></title> |
|
|
|
<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> will |
|
create a <interfacename>PersistenceUnitInfo</interfacename> 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 DataSources outside of JNDI and to control the weaving |
|
process.</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>A typical <literal>persistence.xml</literal> file looks as |
|
follows:</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> |
|
|
|
<para><emphasis>NOTE: The "exclude-unlisted-classes" element always |
|
indicates that NO scanning for annotated entity classes is supposed to |
|
happen, in order to support the |
|
<literal><exclude-unlisted-classes/></literal> shortcut. This is |
|
in line with the JPA specification (which suggests that shortcut) but |
|
unfortunately in conflict with the JPA XSD (which implies "false" for |
|
that shortcut). As a consequence, |
|
"<literal><exclude-unlisted-classes> false |
|
</exclude-unlisted-classes/></literal>" is not supported! Simply |
|
omit the "exclude-unlisted-classes" element if you would like entity |
|
class scanning to actually happen.</emphasis></para> |
|
|
|
<para>This 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, etc. However, it also |
|
imposes requirements onto the runtime environment, such as the |
|
availability of a weaving-capable ClassLoader if the persistence |
|
provider demands byte-code transformation.</para> |
|
|
|
<para>Note that this option may conflict with the built-in JPA |
|
capabilities of a Java EE 5 server. So when running in a full Java EE |
|
5 environment, consider obtaining your |
|
<interfacename>EntityManagerFactory</interfacename> from JNDI. |
|
Alternatively, specify a custom "persistenceXmlLocation" on your |
|
<classname>LocalContainerEntityManagerFactoryBean</classname> |
|
definition, e.g. "META-INF/my-persistence.xml", and only include a |
|
descriptor with that name in your application jar files. Since the |
|
Java EE 5 server will only look for default |
|
<literal>META-INF/persistence.xml</literal> files, it will ignore such |
|
custom persistence units and hence avoid conflicts with a |
|
Spring-driven JPA setup upfront. (This applies to Resin 3.1, for |
|
example.)</para> |
|
|
|
<para><emphasis>Use this option for full JPA capabilities in a |
|
Spring-based application environment. This includes web containers |
|
such as Tomcat as well as standalone applications and integration |
|
tests with sophisticated persistence requirements.</emphasis></para> |
|
|
|
<sidebar> |
|
<title>When is load-time weaving required?</title> |
|
|
|
<para>Not all JPA providers impose the need of a JVM agent |
|
(Hibernate being an example). If your provider does not require an |
|
agent or you have other alternatives (for example 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 on the environment (web |
|
container/application server). 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> |
|
is typically not efficient - the agents work against the |
|
<emphasis>entire virtual machine</emphasis> and inspect |
|
<emphasis>every</emphasis> class that is loaded - something that is |
|
typically undesirable in a production server enviroment.</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 ClassLoader</emphasis> and not per |
|
VM.</para> |
|
|
|
<para>The following sections will discuss typical JPA weaving setup on |
|
Tomcat as well as using Spring's VM agent. See the AOP chapter section |
|
entitled <xref linkend="aop-aj-ltw-spring" /> for details on how to |
|
set up general load-time weaving, covering Tomcat and the VM agent as |
|
well as WebLogic, OC4J, GlassFish and Resin.</para> |
|
|
|
<section id="orm-jpa-setup-lcemfb-tomcat"> |
|
<title>Tomcat load-time weaving setup (5.0+)</title> |
|
|
|
<para><ulink url="http://tomcat.apache.org/">Apache Tomcat's</ulink> |
|
default ClassLoader does not support class transformation but allows |
|
custom ClassLoaders to be used. Spring offers the |
|
<classname>TomcatInstrumentableClassLoader</classname> (inside the |
|
<literal>org.springframework.instrument.classloading.tomcat</literal> |
|
package) which extends the Tomcat ClassLoader |
|
(<classname>WebappClassLoader</classname>) and allows JPA |
|
<classname>ClassTransformer</classname> instances to 'enhance' all |
|
classes loaded by it. In short, JPA transformers will be applied |
|
only inside a specific web application (which uses the |
|
<classname>TomcatInstrumentableClassLoader</classname>).</para> |
|
|
|
<para>In order to use the custom ClassLoader on:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>Tomcat 5.0.x/5.5.x</para> |
|
</listitem> |
|
|
|
<orderedlist> |
|
<listitem> |
|
<para>Copy <literal>spring-tomcat-weaver.jar</literal> into |
|
<emphasis>$CATALINA_HOME</emphasis>/server/lib (where |
|
<emphasis>$CATALINA_HOME</emphasis> represents the root of the |
|
Tomcat installation).</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Instruct Tomcat to use the custom ClassLoader (instead |
|
of the default one) by editing the web application context |
|
file:</para> |
|
|
|
<programlisting language="xml"><Context path="/myWebApp" docBase="/my/webApp/location"> |
|
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> |
|
</Context></programlisting> |
|
|
|
<para>Tomcat 5.0.x and 5.5.x series support several context |
|
locations: server configuration file |
|
(<emphasis>$CATALINA_HOME/conf/server.xml</emphasis>), the |
|
default context configuration |
|
(<emphasis>$CATALINA_HOME/conf/context.xml</emphasis>) that |
|
affects all deployed web applications and per-webapp |
|
configurations, deployed on the server |
|
<emphasis>($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml</emphasis>) |
|
side or along with the webapp |
|
(<emphasis>your-webapp.war/META-INF/context.xml</emphasis>). |
|
For efficiency, inside the web-app configuration style is |
|
recommended since only applications which use JPA will use the |
|
custom ClassLoader. See the Tomcat 5.x <ulink |
|
url="http://tomcat.apache.org/tomcat-5.5-doc/config/context.html">documentation</ulink> |
|
for more details about available context locations.</para> |
|
|
|
<para>Note that versions prior to 5.5.20 contained a bug in |
|
the XML configuration parsing preventing usage of |
|
<literal>Loader</literal> tag inside |
|
<emphasis>server.xml</emphasis> (no matter if a ClassLoader is |
|
specified or not (be it the official or a custom one). See |
|
Tomcat's bugzilla for <ulink |
|
url="http://issues.apache.org/bugzilla/show_bug.cgi?id=39704">more |
|
details</ulink>.</para> |
|
|
|
<para>If you are using Tomcat 5.5.20+ you can set |
|
<emphasis>useSystemClassLoaderAsParent</emphasis> to |
|
<literal>false</literal> to fix the problem: <programlisting |
|
language="xml"><Context path="/myWebApp" docBase="/my/webApp/location"> |
|
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" |
|
useSystemClassLoaderAsParent="false"/> |
|
</Context></programlisting></para> |
|
</listitem> |
|
</orderedlist> |
|
|
|
<listitem> |
|
<para>Tomcat 6.0.x</para> |
|
</listitem> |
|
|
|
<orderedlist> |
|
<listitem> |
|
<para>Copy <literal>spring-tomcat-weaver.jar</literal> into |
|
<emphasis>$CATALINA_HOME</emphasis>/lib (where |
|
<emphasis>$CATALINA_HOME</emphasis> represents the root of the |
|
Tomcat installation).</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Instruct Tomcat to use the custom ClassLoader (instead |
|
of the default one) by editing the web application context |
|
file:</para> |
|
|
|
<programlisting language="xml"><Context path="/myWebApp" docBase="/my/webApp/location"> |
|
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> |
|
</Context></programlisting> |
|
|
|
<para>Tomcat 6.0.x (similar to 5.0.x/5.5.x) series support |
|
several context locations: server configuration file |
|
(<emphasis>$CATALINA_HOME/conf/server.xml</emphasis>), the |
|
default context configuration |
|
(<emphasis>$CATALINA_HOME/conf/context.xml</emphasis>) that |
|
affects all deployed web applications and per-webapp |
|
configurations, deployed on the server |
|
<emphasis>($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml</emphasis>) |
|
side or along with the webapp |
|
(<emphasis>your-webapp.war/META-INF/context.xml</emphasis>). |
|
For efficiency, inside the web-app configuration style is |
|
recommended since only applications which use JPA will use the |
|
custom ClassLoader. See the Tomcat 5.x <ulink |
|
url="http://tomcat.apache.org/tomcat-6.0-doc/config/context.html">documentation</ulink> |
|
for more details about available context locations.</para> |
|
</listitem> |
|
</orderedlist> |
|
</itemizedlist> |
|
|
|
<para>The last step required on all Tomcat versions, is to use the |
|
appropriate the <interfacename>LoadTimeWeaver</interfacename> when |
|
configuring |
|
<classname>LocalContainerEntityManagerFactoryBean</classname>:</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>Using this technique, JPA applications relying on |
|
instrumentation, can run in Tomcat without the need of an agent. |
|
This is important especially when hosting applications which rely on |
|
different JPA implementations since the JPA transformers are applied |
|
only at ClassLoader level and thus, are isolated from each |
|
other.</para> |
|
|
|
<note> |
|
<para>If TopLink Essentials is being used a JPA provider under |
|
Tomcat, please place the toplink-essentials jar under |
|
<emphasis>$CATALINA_HOME</emphasis>/shared/lib folder instead of |
|
your war.</para> |
|
</note> |
|
</section> |
|
|
|
<section id="orm-jpa-setup-lcemfb-agent"> |
|
<title>General load-time weaving using the VM agent</title> |
|
|
|
<para>For environments where class instrumentation is required but |
|
are not supported by the existing LoadTimeWeaver implementations, a |
|
JDK agent can be the only solution. For such cases, Spring provides |
|
<classname>InstrumentationLoadTimeWeaver</classname> which requires |
|
a Spring-specific (but very general) VM agent (<filename |
|
class="libraryfile">spring-agent.jar</filename>):</para> |
|
|
|
<programlisting language="xml"><bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> |
|
<property name="loadTimeWeaver"> |
|
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> |
|
</property> |
|
</bean></programlisting> |
|
|
|
<para>Note that the virtual machine has to be started with the |
|
Spring agent, by supplying the following JVM options:</para> |
|
|
|
<programlisting>-javaagent:/path/to/spring-agent.jar</programlisting> |
|
</section> |
|
|
|
<section id="orm-jpa-setup-lcemfb-weaver"> |
|
<title>Context-wide load-time weaver setup</title> |
|
|
|
<para>Since Spring 2.5, a context-wide |
|
<interfacename>LoadTimeWeaver</interfacename> can be configured |
|
using the <literal>context:load-time-weaver</literal> configuration |
|
element. Such a 'global' weaver will be picked up by all JPA |
|
<classname>LocalContainerEntityManagerFactoryBeans</classname> |
|
automatically.</para> |
|
|
|
<para>This is the preferred way of setting up a load-time weaver, |
|
delivering autodetection of the platform (WebLogic, OC4J, GlassFish, |
|
Tomcat, Resin, VM agent) as well as 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>See the section entitled <xref linkend="aop-aj-ltw-spring" /> |
|
for details on how to set up general load-time weaving, covering |
|
Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and |
|
Resin.</para> |
|
</section> |
|
</section> |
|
|
|
<section id="orm-jpa-multiple-pu"> |
|
<title>Dealing with multiple persistence units</title> |
|
|
|
<para>For applications that rely on multiple persistence units |
|
locations (stored in various jars in the classpath for example), |
|
Spring offers the |
|
<interfacename>PersistenceUnitManager</interfacename> to act as a |
|
central repository and avoid the (potentially expensive) persistence |
|
units discovery process. The default implementation allows multiple |
|
locations to be specified (by default, the classpath is searched for |
|
<filename>'META-INF/persistence.xml'</filename> files) which are |
|
parsed and later on retrieved through the persistence unit |
|
name:</para> |
|
|
|
<programlisting language="xml"><bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"> |
|
<property name="persistenceXmlLocation"> |
|
<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"/> |
|
</bean></programlisting> |
|
|
|
<para>Note that the default implementation allows customization of the |
|
persistence unit infos before feeding them to the JPA provider |
|
declaratively through its 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 will be 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>While <interfacename>EntityManagerFactory</interfacename> |
|
instances are thread-safe, |
|
<interfacename>EntityManager</interfacename> instances are not. The |
|
injected JPA <interfacename>EntityManager</interfacename> behave just |
|
like an <interfacename>EntityManager</interfacename> fetched from an |
|
application server's JNDI environment, as defined by the JPA |
|
specification. It will delegate all calls to the current transactional |
|
<interfacename>EntityManager</interfacename>, if any; else, it will |
|
fall back to a newly created |
|
<interfacename>EntityManager</interfacename> per operation, making it |
|
thread-safe.</para> |
|
</note> |
|
|
|
<para>It is possible to write code against the plain JPA without using |
|
any Spring dependencies, using an injected |
|
<interfacename>EntityManagerFactory</interfacename> or |
|
<interfacename>EntityManager</interfacename>. Note that 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 corresponding DAO implementation 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>Note: As alternative to defining a |
|
<classname>PersistenceAnnotationBeanPostProcessor</classname> |
|
explicitly, consider using Spring 2.5's |
|
<literal>context:annotation-config</literal> XML element in your |
|
application context configuration. This will automatically register all |
|
of Spring's standard post-processors for annotation-based configuration |
|
(including <classname>CommonAnnotationBeanPostProcessor</classname> |
|
etc).</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 issue with such a DAO is that it always creates a new |
|
<interfacename>EntityManager</interfacename> via the factory. This can |
|
be easily overcome by requesting a transactional |
|
<interfacename>EntityManager</interfacename> (also called "shared |
|
EntityManager", since 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>Note that 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, therefore the expression "method/field level |
|
injection". Field-level annotations concise and easier to use while |
|
method-level allow for processing 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 implementation prefers 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.</para> |
|
|
|
<para>The main advantage of this DAO style is that it 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 of course appealing from |
|
a non-invasiveness perspective, and might feel more natural to JPA |
|
developers.</para> |
|
</section> |
|
</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 |
|
"jpaDialect" bean property. In such a scenario, the DAOs won't receive an |
|
<interfacename>EntityManagerFactory</interfacename> reference but rather a |
|
full <classname>JpaTemplate</classname> instance instead (for example, |
|
passed into <classname>JpaDaoSupport</classname>'s "jpaTemplate" |
|
property). 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. Note that the default |
|
implementation used (<classname>DefaultJpaDialect</classname>) doesn't |
|
provide any special capabilities and if the above features are required, |
|
the appropriate dialect has to be specified.</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 id="orm-jpa-tx"> |
|
<title>Transaction Management</title> |
|
|
|
<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-2.5.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> |
|
|
|
<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-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 just |
|
as with JDBC or other ORM technologies, the iBATIS support works with |
|
Spring's exception hierarchy and let's you enjoy the all IoC features |
|
Spring has.</para> |
|
|
|
<para>Transaction management can be handled through Spring's standard |
|
facilities. There are no special transaction strategies for iBATIS, as |
|
there is 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 were |
|
moved to the Spring Modules project as of Spring 2.0, and you are |
|
directed there for documentation.</para> |
|
</note> |
|
|
|
<section id="orm-ibatis-setup"> |
|
<title>Setting up the <classname>SqlMapClient</classname></title> |
|
|
|
<para>If we want to map the previous Account class 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.</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>Note that a <classname>SqlMapTemplate</classname> instance could |
|
also be created manually, passing in the <literal>SqlMapClient</literal> |
|
as constructor argument. The <literal>SqlMapClientDaoSupport</literal> |
|
base class simply pre-initializes a |
|
<classname>SqlMapClientTemplate</classname> instance for us.</para> |
|
|
|
<para>The <classname>SqlMapClientTemplate</classname> also 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 <literal>SQLException</literal> thrown will automatically get |
|
converted 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>. A corresponding DAO implementation |
|
looks like as follows:</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 such a scenario, the <literal>SQLException</literal> thrown by |
|
the iBATIS API needs to be handled in a custom fashion: usually, |
|
wrapping it in your own application-specific DAO exception. Wiring in |
|
the application context would still look like before, 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>
|
|
|