first cut at re-organizing the ORM chapter; moved outdated sections to new Classic Spring Usage appendix

This commit is contained in:
Thomas Risberg 2009-05-22 16:16:12 +00:00
parent 4cedea6531
commit 62406474e0
3 changed files with 924 additions and 869 deletions

View File

@ -0,0 +1,430 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<appendix id="classic-spring">
<title>Classic Spring Usage</title>
<para>This appendix discusses some classic Spring usage patterns as a
reference for developers maintaining legacy Spring applications. These usage
patterns no longer reflect the recommended way of using these features and
the current recommended usage is covered in the respective sections of the
reference manual.</para>
<section id="classic-spring-orm">
<title>Classic ORM usage</title>
<para>This section documents the classic usage patterns that you might
encounter in a legacy Spring application. For the currently recommended
usage patterns, please refer to the <xref linkend="orm" /> chapter.
</para>
<section id="classic-spring-hibernate">
<title>Hibernate</title>
<para>For the currently recommended usage patterns for Hibernate see
<xref linkend="orm-hibernate" /></para>
<section id="orm-hibernate-template">
<title>The <classname>HibernateTemplate</classname></title>
<para>The basic programming model for templating looks as follows, for
methods that can be part of any custom data access object or business
service. There are no restrictions on the implementation of the
surrounding object at all, it just needs to provide a Hibernate
<interfacename>SessionFactory</interfacename>. It can get the latter
from anywhere, but preferably as bean reference from a Spring IoC
container - via a simple
<methodname>setSessionFactory(..)</methodname> bean property setter.
The following snippets show a DAO definition in a Spring container,
referencing the above defined
<interfacename>SessionFactory</interfacename>, and an example for a
DAO method implementation.</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="sessionFactory" ref="mySessionFactory"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public Collection loadProductsByCategory(String category) throws DataAccessException {
return this.hibernateTemplate.find("from test.Product product where product.category=?", category);
}
}</programlisting>
<para>The <classname>HibernateTemplate</classname> class provides many
methods that mirror the methods exposed on the Hibernate
<interfacename>Session</interfacename> interface, in addition to a
number of convenience methods such as the one shown above. If you need
access to the <interfacename>Session</interfacename> to invoke methods
that are not exposed on the <classname>HibernateTemplate</classname>,
you can always drop down to a callback-based approach like so.</para>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
Criteria criteria = session.createCriteria(Product.class);
criteria.add(Expression.eq("category", category));
criteria.setMaxResults(6);
return criteria.list();
}
};
}
}</programlisting>
<para>A callback implementation effectively can be used for any
Hibernate data access. <classname>HibernateTemplate</classname> will
ensure that <interfacename>Session</interfacename> instances are
properly opened and closed, and automatically participate in
transactions. The template instances are thread-safe and reusable,
they can thus be kept as instance variables of the surrounding class.
For simple single step actions like a single find, load, saveOrUpdate,
or delete call, <classname>HibernateTemplate</classname> offers
alternative convenience methods that can replace such one line
callback implementations. Furthermore, Spring provides a convenient
<classname>HibernateDaoSupport</classname> base class that provides a
<methodname>setSessionFactory(..)</methodname> method for receiving a
<interfacename>SessionFactory</interfacename>, and
<methodname>getSessionFactory()</methodname> and
<methodname>getHibernateTemplate()</methodname>for use by subclasses.
In combination, this allows for very simple DAO implementations for
typical requirements:</para>
<programlisting language="java">public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
return this.getHibernateTemplate().find(
"from test.Product product where product.category=?", category);
}
}</programlisting>
</section>
<section id="orm-hibernate-daos">
<title>Implementing Spring-based DAOs without callbacks</title>
<para>As alternative to using Spring's
<classname>HibernateTemplate</classname> to implement DAOs, data
access code can also be written in a more traditional fashion, without
wrapping the Hibernate access code in a callback, while still
respecting and participating in Spring's generic
<classname>DataAccessException</classname> hierarchy. The
<classname>HibernateDaoSupport</classname> base class offers methods
to access the current transactional
<interfacename>Session</interfacename> and to convert exceptions in
such a scenario; similar methods are also available as static helpers
on the <classname>SessionFactoryUtils</classname> class. Note that
such code will usually pass '<literal>false</literal>' as the value of
the <methodname>getSession(..)</methodname> methods
'<literal>allowCreate</literal>' argument, to enforce running within a
transaction (which avoids the need to close the returned
<interfacename>Session</interfacename>, as its lifecycle is managed by
the transaction).</para>
<programlisting language="java">public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException, MyException {
Session session = getSession(false);
try {
Query query = session.createQuery("from test.Product product where product.category=?");
query.setString(0, category);
List result = query.list();
if (result == null) {
throw new MyException("No search results.");
}
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
}
}</programlisting>
<para>The advantage of such direct Hibernate access code is that it
allows <emphasis>any</emphasis> checked application exception to be
thrown within the data access code; contrast this to the
<classname>HibernateTemplate</classname> class which is restricted to
throwing only unchecked exceptions within the callback. Note that you
can often defer the corresponding checks and the throwing of
application exceptions to after the callback, which still allows
working with <classname>HibernateTemplate</classname>. In general, the
<classname>HibernateTemplate</classname> class' convenience methods
are simpler and more convenient for many scenarios.</para>
</section>
</section>
<section id="classic-spring-jpa">
<title>JPA</title>
<para>For the currently recommended usage patterns for JPA see <xref
linkend="orm-jpa" /></para>
<section id="orm-jpa-template">
<title><classname>JpaTemplate</classname> and
<classname>JpaDaoSupport</classname></title>
<para>Each JPA-based DAO will then receive a
<interfacename>EntityManagerFactory</interfacename> via dependency
injection. Such a DAO can be coded against plain JPA and work with the
given <interfacename>EntityManagerFactory</interfacename> or through
Spring's <classname>JpaTemplate</classname>:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="entityManagerFactory" ref="myEmf"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<programlisting language="java">public class JpaProductDao implements ProductDao {
private JpaTemplate jpaTemplate;
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.jpaTemplate = new JpaTemplate(emf);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return (Collection) this.jpaTemplate.execute(new JpaCallback() {
public Object doInJpa(EntityManager em) throws PersistenceException {
Query query = em.createQuery("from Product as p where p.category = :category");
query.setParameter("category", category);
List result = query.getResultList();
<lineannotation>// do some further processing with the result list</lineannotation>
return result;
}
});
}
}</programlisting>
<para>The <interfacename>JpaCallback</interfacename> implementation
allows any type of JPA data access. The
<classname>JpaTemplate</classname> will ensure that
<interfacename>EntityManager</interfacename>s are properly opened and
closed and automatically participate in transactions. Moreover, the
<classname>JpaTemplate</classname> properly handles exceptions, making
sure resources are cleaned up and the appropriate transactions rolled
back. The template instances are thread-safe and reusable and they can
be kept as instance variable of the enclosing class. Note that
<classname>JpaTemplate</classname> offers single-step actions such as
find, load, merge, etc along with alternative convenience methods that
can replace one line callback implementations.</para>
<para>Furthermore, Spring provides a convenient
<classname>JpaDaoSupport</classname> base class that provides the
<literal>get/setEntityManagerFactory</literal> and
<methodname>getJpaTemplate()</methodname> to be used by
subclasses:</para>
<programlisting language="java">public class ProductDaoImpl extends JpaDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
Map&lt;String, String&gt; params = new HashMap&lt;String, String&gt;();
params.put("category", category);
return getJpaTemplate().findByNamedParams("from Product as p where p.category = :category", params);
}
}</programlisting>
<para>Besides working with Spring's
<classname>JpaTemplate</classname>, one can also code Spring-based
DAOs against the JPA, doing one's own explicit
<interfacename>EntityManager</interfacename> handling. As also
elaborated in the corresponding Hibernate section, the main advantage
of this approach is that your data access code is able to throw
checked exceptions. <classname>JpaDaoSupport</classname> offers a
variety of support methods for this scenario, for retrieving and
releasing a transaction <interfacename>EntityManager</interfacename>,
as well as for converting exceptions.</para>
<para><emphasis>JpaTemplate mainly exists as a sibling of JdoTemplate
and HibernateTemplate, offering the same style for people used to
it.</emphasis></para>
</section>
</section>
<section id="classic-spring-jdo">
<title>JDO</title>
<para>For the currently recommended usage patterns for JDO see <xref
linkend="orm-jdo" /></para>
<section id="orm-jdo-template">
<title><classname>JdoTemplate</classname> and
<classname>JdoDaoSupport</classname></title>
<para>Each JDO-based DAO will then receive the
<interfacename>PersistenceManagerFactory</interfacename> through
dependency injection. Such a DAO could be coded against plain JDO API,
working with the given
<interfacename>PersistenceManagerFactory</interfacename>, but will
usually rather be used with the Spring Framework's
<classname>JdoTemplate</classname>:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="myProductDao" class="product.ProductDaoImpl"&gt;
&lt;property name="persistenceManagerFactory" ref="myPmf"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
private JdoTemplate jdoTemplate;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.jdoTemplate = new JdoTemplate(pmf);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return (Collection) this.jdoTemplate.execute(new JdoCallback() {
public Object doInJdo(PersistenceManager pm) throws JDOException {
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
List result = query.execute(category);
<lineannotation>// do some further stuff with the result list</lineannotation>
return result;
}
});
}
}</programlisting>
<para>A callback implementation can effectively be used for any JDO
data access. <classname>JdoTemplate</classname> will ensure that
<classname>PersistenceManager</classname>s are properly opened and
closed, and automatically participate in transactions. The template
instances are thread-safe and reusable, they can thus be kept as
instance variables of the surrounding class. For simple single-step
actions such as a single <literal>find</literal>,
<literal>load</literal>, <literal>makePersistent</literal>, or
<literal>delete</literal> call, <classname>JdoTemplate</classname>
offers alternative convenience methods that can replace such one line
callback implementations. Furthermore, Spring provides a convenient
<classname>JdoDaoSupport</classname> base class that provides a
<literal>setPersistenceManagerFactory(..)</literal> method for
receiving a <classname>PersistenceManagerFactory</classname>, and
<methodname>getPersistenceManagerFactory()</methodname> and
<methodname>getJdoTemplate()</methodname> for use by subclasses. In
combination, this allows for very simple DAO implementations for
typical requirements:</para>
<programlisting language="java">public class ProductDaoImpl extends JdoDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
return getJdoTemplate().find(
Product.class, "category = pCategory", "String category", new Object[] {category});
}
}</programlisting>
<para>As alternative to working with Spring's
<classname>JdoTemplate</classname>, you can also code Spring-based
DAOs at the JDO API level, explicitly opening and closing a
<interfacename>PersistenceManager</interfacename>. As elaborated in
the corresponding Hibernate section, the main advantage of this
approach is that your data access code is able to throw checked
exceptions. <classname>JdoDaoSupport</classname> offers a variety of
support methods for this scenario, for fetching and releasing a
transactional <interfacename>PersistenceManager</interfacename> as
well as for converting exceptions.</para>
</section>
</section>
<section id="classic-spring-ibatis">
<title>iBATIS</title>
<para>For the currently recommended usage patterns for iBATIS see <xref
linkend="orm-ibatis" /></para>
<section id="orm-ibatis-template">
<title>Using <classname>SqlMapClientTemplate</classname> and
<classname>SqlMapClientDaoSupport</classname></title>
<para>The <classname>SqlMapClientDaoSupport</classname> class offers a
supporting class similar to the
<classname>SqlMapDaoSupport</classname>. We extend it to implement our
DAO:</para>
<programlisting language="java">public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {
public Account getAccount(String email) throws DataAccessException {
return (Account) getSqlMapClientTemplate().queryForObject("getAccountByEmail", email);
}
public void insertAccount(Account account) throws DataAccessException {
getSqlMapClientTemplate().update("insertAccount", account);
}
}</programlisting>
<para>In the DAO, we use the pre-configured
<classname>SqlMapClientTemplate</classname> to execute the queries,
after setting up the <literal>SqlMapAccountDao</literal> in the
application context and wiring it with our
<literal>SqlMapClient</literal> instance:</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="accountDao" class="example.SqlMapAccountDao"&gt;
&lt;property name="sqlMapClient" ref="sqlMapClient"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>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>
</section>
<section id="clasic-spring-mvc">
<title>Classic Spring MVC</title>
<para>...</para>
</section>
</appendix>

File diff suppressed because it is too large Load Diff

View File

@ -330,6 +330,7 @@
<xi:include href="metadata.xml"/>
</part>
<!-- back matter -->
<xi:include href="classic-spring.xml"/>
<xi:include href="xsd-configuration.xml"/>
<xi:include href="xml-custom.xml"/>
<xi:include href="dtd.xml"/>