2083 lines
99 KiB
XML
2083 lines
99 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
|
<chapter id="orm">
|
|
<title>Object Relational Mapping (ORM) data access</title>
|
|
|
|
<section id="orm-introduction">
|
|
<title>Introduction</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>
|