| | + title | Ref. /chapter[1]/title[1] |
| Original | Traduction | Data Access using O/R Mappers |
| sect1
| | + title | Ref. /chapter[1]/sect1[1]/title[1] |
| Original | Traduction | Introduction |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1] |
| Original | Traduction | Spring provides integration with Hibernate, JDO, and iBATIS SQL Maps
in terms of resource management, DAO implementation support, and
transaction strategies. For Hibernate there is first-class support with
lots of IoC convenience features, addressing many typical Hibernate
integration issues. All of these comply with Spring's generic transaction
and DAO exception hierarchies. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[2] |
| Original | Traduction | Spring's 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 an ApplicationContext or BeanFactory does provide additional
benefits in terms of ease of configuration and deployment; as such, most
examples in this section show configuration inside an
ApplicationContext. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[3] |
| Original | Traduction | Some of the the benefits of using Spring to create your O/R mapping
applications include: |
|
| + para | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | To avoid vendor lock-in, and allow mix-and-match
implementation strategies. While Hibernate is powerful,
flexible, open source and free, it still uses a proprietary API.
Furthermore one could argue that iBatis is a bit lightweight, although
it's excellent for use in application that don't require complex O/R
mapping strategies. Given the choice, it's usually desirable to
implement major application functionality using standard or abstracted
APIs, in case you need to switch to another implementation for reasons
of functionality, performance, or any other concerns. For example,
Spring's abstraction of Hibernate Transactions and Exceptions, along
with its IoC approach which allows you to easily swap in mapper/DAO
objects implementing data-access functionality, makes it easy to
isolate all Hibernate-specific code in one area of your application,
without sacrificing any of the power of Hibernate. Higher level
service code dealing with the DAOs has no need to know anything about
their implementation. This approach has the additional benefit of
making it easy to intentionally implement data-access with a
mix-and-match approach (i.e. some data-access performed using
Hibernate, and some using JDBC, others using iBatis) in a
non-intrusive fashion, potentially providing great benefits in terms
of continuing to use legacy code or leveraging the strength of each
technology. |
|
| + para | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Ease of testing. Spring's inversion of
control approach makes it easy to swap the implementations and
locations of Hibernate session factories, datasources, transaction
managers, and mapper object implementations (if needed). This makes it
much easier to isolate and test each piece of persistence-related code
in isolation. |
|
| + para | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | General resource management. Spring
application contexts can handle the location and configuration of
Hibernate SessionFactories, JDBC datasources, iBatis SQLMaps
configuration objects, and other related resources. This makes these
values easy to manage and change. Spring offers efficient, easy and
safe handling of Hibernate Sessions. Related code using Hibernate
generally needs to use the same Hibernate Session object for
efficiency and proper transaction handling. Spring makes it easy to
transparently create and bind a session to the current thread, using
either a declarative, AOP method interceptor approach, or by using an
explicit, template wrapper class at the Java code level. Thus Spring
solves many of the usage issues that repeatedly arise on the Hibernate
forums. |
|
| + para | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | Exception wrapping. Spring can wrap
exceptions from you O/R mapping tool of choice, converting them from
proprietary, checked exceptions, to a set of abstracted runtime
exceptions. 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 | Ref. /chapter[1]/sect1[1]/itemizedlist[1]/listitem[5]/para[1] |
| Original | Traduction | Integrated transaction management. 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 related code being affected. As an
added benefit, JDBC-related code can fully integrate transactionally
with the code you use to do O/R mapping. This is useful for handling
functionality not implemented in, for example, Hibernate or iBatis.
|
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[2]/title[1] |
| Original | Traduction | Hibernate |
| sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[1]/title[1] |
| Original | Traduction | Resource Management |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[1]/para[1] |
| Original | Traduction | 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: Inversion of control via
templating, i.e. infrastructure classes with callback interfaces, or
applying AOP interceptors. 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 JdbcTemplate class mentioned in a
previous section cares for connection handling, and for proper
conversion of SQLException to the
DataAccessException hierarchy, including
translation of database-specific SQL error codes to meaningful exception
classes. It supports both JTA and JDBC transactions, via respective
Spring transaction managers. Spring also offers Hibernate and JDO
support, consisting of a HibernateTemplate /
JdoTemplate analogous to
JdbcTemplate, a
HibernateInterceptor /
JdoInterceptor, and a Hibernate / JDO transaction
manager. 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 object 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 app,
many important objects are JavaBeans: data access templates, data access
objects (that use the templates), transaction managers, business objects
(that use the data access objects and transaction managers), web view
resolvers, web controllers (that use the business objects), etc. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[2]/title[1] |
| Original | Traduction | Resource Definitions in an Application Context |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[2]/para[1] |
| Original | Traduction | To avoid tying application objects to hard-coded resource lookups,
Spring allows you to define resources like a JDBC DataSource or a
Hibernate SessionFactory as beans in an application context. 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
DataSource and a Hibernate
SessionFactory on top of it: |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[2]/programlisting[1] |
| Original | Traduction | <beans>
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myds</value>
</property>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource"/>
</property>
</bean>
...
</beans> |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[2]/para[2] |
| Original | Traduction | Note that switching from a JNDI-located
DataSource to a locally defined one like a
Jakarta Commons DBCP BasicDataSource is just a
matter of configuration: |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[2]/programlisting[2] |
| Original | Traduction | <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:hsql://localhost:9001</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean> |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[2]/para[3] |
| Original | Traduction | You can also use a JNDI-located
SessionFactory, but that's typically not
necessary outside an EJB context (see the "container resources vs local
resources" section for a discussion). |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[3]/title[1] |
| Original | Traduction | Inversion of Control: Template and Callback |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[3]/para[1] |
| Original | Traduction | The basic programming model for templating looks as follows, for
methods that can be part of any custom data access object or business
object. There are no restrictions on the implementation of the
surrounding object at all, it just needs to provide a Hibernate
SessionFactory. It can get the latter from
anywhere, but preferably as bean reference from a Spring application
context - via a simple setSessionFactory bean
property setter. The following snippets show a DAO definition in a
Spring application context, referencing the above defined
SessionFactory, and an example for a DAO method
implementation. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[3]/programlisting[1] |
| Original | Traduction | <beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
...
</beans> |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[3]/programlisting[2] |
| Original | Traduction | public class ProductDaoImpl implements ProductDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List loadProductsByCategory(final String category) {
HibernateTemplate hibernateTemplate =
new HibernateTemplate(this.sessionFactory);
return (List) hibernateTemplate.execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
List result = session.find(
"from test.Product product where product.category=?",
category, Hibernate.STRING);
// do some further stuff with the result list
return result;
}
}
);
}
} |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[3]/para[2] |
| Original | Traduction | A callback implementation can effectively be used for any
Hibernate data access. HibernateTemplate will
ensure that Sessions 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,
HibernateTemplate offers alternative convenience
methods that can replace such one line callback implementations.
Furthermore, Spring provides a convenient
HibernateDaoSupport base class that provides a
setSessionFactory method for receiving a
SessionFactory, and getSessionFactory and
getHibernateTemplate for use by subclasses. In
combination, this allows for very simple DAO implementations for typical
requirements: |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[3]/programlisting[3] |
| Original | Traduction | public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
public List loadProductsByCategory(String category) {
return getHibernateTemplate().find(
"from test.Product product where product.category=?", category,
Hibernate.STRING);
}
} |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[4]/title[1] |
| Original | Traduction | Applying an AOP Interceptor Instead of a Template |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[4]/para[1] |
| Original | Traduction | An alternative to using a HibernateTemplate
is Spring's AOP HibernateInterceptor, replacing
the callback implementation with straight Hibernate code within a
delegating try/catch block, and a respective interceptor configuration
in the application context. The following snippets show respective DAO,
interceptor, and proxy definitions in a Spring application context, and
an example for a DAO method implementation. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[4]/programlisting[1] |
| Original | Traduction | <beans>
...
<bean id="myHibernateInterceptor"
class="org.springframework.orm.hibernate.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myProductDaoTarget" class="product.ProductDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myProductDao" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>product.ProductDao</value>
</property>
<property name="interceptorNames">
<list>
<value>myHibernateInterceptor</value>
<value>myProductDaoTarget</value>
</list>
</property>
</bean>
...
</beans> |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[4]/programlisting[2] |
| Original | Traduction | public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
public List loadProductsByCategory(final String category) throws MyException {
Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
try {
List result = session.find(
"from test.Product product where product.category=?",
category, Hibernate.STRING);
if (result == null) {
throw new MyException("invalid search result");
}
return result;
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
} |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[4]/para[2] |
| Original | Traduction | This method will only work with a
HibernateInterceptor for it, caring for opening a
thread-bound Session before and closing it after the method call. The
"false" flag on getSession makes sure that the Session must already
exist; otherwise SessionFactoryUtils would create
a new one if none was found. If there is already a
SessionHolder bound to the thread, e.g. by a
HibernateTransactionManager transaction,
SessionFactoryUtils automatically takes part in
it in any case. HibernateTemplate uses
SessionFactoryUtils internally - it's all the
same infrastructure. The major advantage of
HibernateInterceptor is that it allows any
checked application exception to be thrown within the data access code,
while HibernateTemplate is restricted to unchecked exceptions within the
callback. Note that one can often defer the respective checks and
throwing of application exceptions to after the callback, though. The
interceptor's major drawback is that it requires special setup in the
context. HibernateTemplate's convenience methods
offers simpler means for many scenarios. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[5]/title[1] |
| Original | Traduction | Programmatic Transaction Demarcation |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[5]/para[1] |
| Original | Traduction | On top of such lower-level data access services, transactions can
be demarcated in a higher level of the application, spanning any number
of operations. There are no restrictions on the implementation of the
surrounding business object here too, it just needs a Spring
PlatformTransactionManager. Again, the latter can
come from anywhere, but preferably as bean reference via a
setTransactionManager method - just like the
productDAO should be set via a
setProductDao method. The following snippets
show a transaction manager and a business object definition in a Spring
application context, and an example for a business method
implementation. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[5]/programlisting[1] |
| Original | Traduction | <beans>
...
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="productDao">
<ref bean="myProductDao"/>
</property>
</bean>
</beans> |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[5]/programlisting[2] |
| Original | Traduction | public class ProductServiceImpl implements ProductService {
private PlatformTransactionManager transactionManager;
private ProductDao productDao;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
public void increasePriceOfAllProductsInCategory(final String category) {
TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(
new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
List productsToChange = productDAO.loadProductsByCategory(category);
...
}
}
);
}
} |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[6]/title[1] |
| Original | Traduction | Declarative Transaction Demarcation |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[6]/para[1] |
| Original | Traduction | Alternatively, one can use Spring's AOP TransactionInterceptor,
replacing the transaction demarcation code with an interceptor
configuration in the application context. This allows you to keep
business objects free of repetitive transaction demarcation code in each
business method. Furthermore, transaction semantics like propagation
behavior and isolation level can be changed in a configuration file and
do not affect the business object implementations. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[6]/programlisting[1] |
| Original | Traduction | <beans>
...
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myTransactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="transactionAttributeSource">
<value>
product.ProductService.increasePrice*=PROPAGATION_REQUIRED
product.ProductService.someOtherBusinessMethod=PROPAGATION_MANDATORY
</value>
</property>
</bean>
<bean id="myProductServiceTarget" class="product.ProductServiceImpl">
<property name="productDao">
<ref bean="myProductDao"/>
</property>
</bean>
<bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>product.ProductService</value>
</property>
<property name="interceptorNames">
<list>
<value>myTransactionInterceptor</value>
<value>myProductServiceTarget</value>
</list>
</property>
</bean>
</beans> |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[6]/programlisting[2] |
| Original | Traduction | public class ProductServiceImpl implements ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
public void increasePriceOfAllProductsInCategory(final String category) {
List productsToChange = this.productDAO.loadProductsByCategory(category);
...
}
...
} |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[6]/para[2] |
| Original | Traduction | As with HibernateInterceptor,
TransactionInterceptor allows any checked
application exception to be thrown with the callback code, while
TransactionTemplate is restricted to unchecked
exceptions within the callback.
TransactionTemplate will trigger a rollback in
case of an unchecked application exception, or if the transaction has
been marked rollback-only by the application (via
TransactionStatus).
TransactionInterceptor behaves the same way by
default but allows configurable rollback policies per method. A
convenient alternative way of setting up declarative transactions is
TransactionProxyFactoryBean, particularly if
there are no other AOP interceptors involved.
TransactionProxyFactoryBean combines the proxy
definition itself with transaction configuration for a particular target
bean. This reduces the configuration effort to one target bean plus one
proxy bean. Furthermore, you do not need to specify which interfaces or
classes the transactional methods are defined in. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[6]/programlisting[3] |
| Original | Traduction | <beans>
...
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myProductServiceTarget" class="product.ProductServiceImpl">
<property name="productDao">
<ref bean="myProductDao"/>
</property>
</bean>
<bean id="myProductService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="target">
<ref bean="myProductServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
<prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop>
</props>
</property>
</bean>
</beans> |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[7]/title[1] |
| Original | Traduction | Transaction Management Strategies |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[7]/para[1] |
| Original | Traduction | Both TransactionTemplate and
TransactionInterceptor delegate the actual
transaction handling to a
PlatformTransactionManager instance, which can be
a HibernateTransactionManager (for a single
Hibernate SessionFactory, using a ThreadLocal Session under the hood) or
a JtaTransactionManager (delegating to the JTA
subsystem of the container) for Hibernate applications. You could even
use a custom PlatformTransactionManager
implementation. So switching from native Hibernate transaction
management to JTA, i.e. 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. For distributed transactions across
multiple Hibernate session factories, simply combine
JtaTransactionManager as a transaction strategy
with multiple LocalSessionFactoryBean
definitions. Each of your DAOs then gets one specific SessionFactory
reference passed into its respective bean property. If all underlying
JDBC data sources are transactional container ones, a business object
can demarcate transactions across any number of DAOs and any number of
session factories without special regard, as long as it is using
JtaTransactionManager as the strategy. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/sect2[7]/programlisting[1] |
| Original | Traduction | <beans>
<bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myds1</value>
</property>
</bean>
<bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myds2</value>
</property>
</bean>
<bean id="mySessionFactory1" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource1"/>
</property>
</bean>
<bean id="mySessionFactory2" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>inventory.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource2"/>
</property>
</bean>
<bean id="myTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory1"/>
</property>
</bean>
<bean id="myInventoryDao" class="product.InventoryDaoImpl">
<property name="sessionFactory">
<ref bean="mySessionFactory2"/>
</property>
</bean>
<bean id="myProductServiceTarget" class="product.ProductServiceImpl">
<property name="productDao">
<ref bean="myProductDao"/>
</property>
<property name="inventoryDao">
<ref bean="myInventoryDao"/>
</property>
</bean>
<bean id="myProductService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="target">
<ref bean="myProductServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
<prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop>
</props>
</property>
</bean>
</beans> |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[7]/para[2] |
| Original | Traduction | Both HibernateTransactionManager and
JtaTransactionManager 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). Additionally,
HibernateTransactionManager can export the JDBC
Connection used by Hibernate to plain JDBC access code. This allows for
high level transaction demarcation with mixed Hibernate/JDBC data access
completely without JTA, as long as just accessing one database! |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[7]/para[3] |
| Original | Traduction | Note, for an alternative approach to using
TransactionProxyFactoryBean to declaratively
demarcate transactions, please see . |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[8]/title[1] |
| Original | Traduction | Container Resources versus Local Resources |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[8]/para[1] |
| Original | Traduction | Spring's resource management allows for simple switching between a
JNDI SessionFactory and a local one, same for a JNDI DataSource, without
having to change a single line of application code. 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 SessionFactory, a manually registered JNDI
SessionFactory does not provide any benefits. If registered via
Hibernate's JCA connector, there is the added value of transparently
taking part in JTA transactions, especially within EJBs. 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 too. JTA does not just
involve container dependencies in terms of JTA itself and of JNDI
DataSources. For non-Spring JTA-driven Hibernate transactions, you have
to use the Hibernate JCA connector, or extra Hibernate transaction code
with JTATransaction being configured, for proper JVM-level caching.
Spring-driven transactions can work with a locally defined Hibernate
SessionFactory nicely, just like with a local JDBC DataSource - 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 e.g. WebLogic
Express does not provide JCA. A Spring app 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. All things considered: If you do not
use EJB, stick with local SessionFactory setup and Spring's
HibernateTransactionManager or
JtaTransactionManager. You will get all benefits
including proper transactional JVM-level caching and distributed
transactions, without any container deployment hassle. JNDI registration
of a Hibernate SessionFactory via the JCA connector only adds value for
use within EJBs. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[2]/sect2[9]/title[1] |
| Original | Traduction | Samples |
|
| + para | Ref. /chapter[1]/sect1[2]/sect2[9]/para[1] |
| Original | Traduction | The Petclinic sample in the Spring distribution offers alternative
DAO implementations and application context configurations for Hibernate,
JDBC, and Apache OJB. Petclinic can therefore serve as working sample
app that illustrates the use of Hibernate in a Spring web app. It also
leverages declarative transaction demarcation with different transaction
strategies. |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[3]/title[1] |
| Original | Traduction | JDO |
|
| + para | Ref. /chapter[1]/sect1[3]/para[1] |
| Original | Traduction | ToDo |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[4]/title[1] |
| Original | Traduction | iBATIS |
|
| + para | Ref. /chapter[1]/sect1[4]/para[1] |
| Original | Traduction | Through the org.springframework.orm.ibatis package,
Spring supports iBATIS SqlMaps 1.3.x and 2.0. The iBATIS support much
resembles Hibernate support in that it supports the same template style
programming and just as with Hibernate, iBatis support works with Spring's
exception hierarchy and let's you enjoy the all IoC features Spring
has. |
| sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[1]/title[1] |
| Original | Traduction | Overview and differences between 1.3.x and 2.0 |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1] |
| Original | Traduction | Spring supports both iBATIS SqlMaps 1.3 and 2.0. First let's have a
look at the differences between the two.
| + title | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/title[1] |
| Original | Traduction | iBATIS SqlMaps supporting classes for 1.3 and 2.0 |
|
| + entry | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/tgroup[1]/thead[1]/row[1]/entry[1] |
| Original | Traduction | Feature |
|
| + entry | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/tgroup[1]/thead[1]/row[1]/entry[2] |
| Original | Traduction | 1.3.x |
|
| + entry | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/tgroup[1]/thead[1]/row[1]/entry[3] |
| Original | Traduction | 2.0 |
|
| + entry | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[1] |
| Original | Traduction | Creation of SqlMap |
|
SqlMapFactoryBean
SqlMapClientFactoryBean
| + entry | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[1] |
| Original | Traduction | Template-style helper class |
|
SqlMapTemplate
SqlMapClientTemplate
| + entry | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[1] |
| Original | Traduction | Callback to use MappedStatement |
|
SqlMapCallback
SqlMapClientCallback
| + entry | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/table[1]/tgroup[1]/tbody[1]/row[4]/entry[1] |
| Original | Traduction | Super class for DAOs |
|
SqlMapDaoSupport
SqlMapClientDaoSupport
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[2]/title[1] |
| Original | Traduction | Setting up the SqlMap |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[2]/para[1] |
| Original | Traduction |
Using iBATIS SqlMaps involves creating SqlMap configuration files containing statements
and result maps. Spring takes care of loading those using the SqlMapFactoryBean
or SqlMapClientFactoryBean where the latter is to be used in combination
with SqlMaps 2.0.
|
|
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[2]/programlisting[1] |
| Original | Traduction |
public class Account {
private String name;
private String email;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
} |
|
Suppose we would want to map this class. We'd have to create the following SqlMap.
Using the query, we can later on retrieve users through their email addresses.
Account.xml:
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[2]/programlisting[2] |
| Original | Traduction |
<sql-map name="Account">
<result-map name="result" class="examples.Account">
<property name="name" column="NAME" columnIndex="1"/>
<property name="email" column="EMAIL" columnIndex="2"/>
</result-map>
<mapped-statement name="getAccountByEmail" result-map="result">
select
ACCOUNT.NAME,
ACCOUNT.EMAIL
from ACCOUNT
where ACCOUNT.EMAIL = #value#
</mapped-statement>
<mapped-statement name="insertAccount">
insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
</mapped-statement>
</sql-map>
|
|
After having defined the Sql Map, we have to create a configuration file for iBATIS
(sqlmap-config.xml):
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[2]/programlisting[3] |
| Original | Traduction |
<sql-map-config>
<sql-map resource="example/Account.xml"/>
</sql-map-config>
|
|
iBATIS loads resources from the classpath so be sure to add the Account.xml file to the
classpath somewhere.
| + para | Ref. /chapter[1]/sect1[4]/sect2[2]/para[3] |
| Original | Traduction |
Using Spring, we can now very easily set up the SqlMap, using the
SqlMapFactoryBean:
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[3]/programlisting[1] |
| Original | Traduction |
<bean id="sqlMap" class="org.springframework.orm.ibatis.SqlMapFactoryBean">
<property name="configLocation"><value>WEB-INF/sqlmap-config.xml</value></property>
</bean>
|
|
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[3]/title[1] |
| Original | Traduction | Using SqlMapDaoSupport |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[1] |
| Original | Traduction |
The SqlMapDaoSupport class offers a supporting class similar to
the HibernateDaoSupport and the JdbcDaoSupport types.
Let's implement a DAO:
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[3]/para[1]/programlisting[1] |
| Original | Traduction |
public class SqlMapAccountDao extends SqlMapDaoSupport implements AccountDao {
public Account getAccount(String email) throws DataAccessException {
return (Account) getSqlMapTemplate().executeQueryForObject("getAccountByEmail", email);
}
public void insertAccount(Account account) throws DataAccessException {
getSqlMapTemplate().executeUpdate("insertAccount", account);
}
}
|
|
As you can see, we're using the SqlMapTemplate to execute the query. Spring has initialized
the SqlMap for us using the SqlMapFactoryBean and when setting up the SqlMapAccountDao
as follows, you're all set to go:
| + programlisting | Ref. /chapter[1]/sect1[4]/sect2[3]/para[1]/programlisting[2] |
| Original | Traduction |
<!-- for more information about using datasource, have a look at the JDBC chapter -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
</bean>
<bean id="accountDao" class="example.SqlMapAccountDao">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="sqlMap"><ref local="sqlMap"/></property>
</bean>
|
|
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[4]/title[1] |
| Original | Traduction | Transaction management |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/para[1] |
| Original | Traduction |
It's pretty easy to add declarative transaction management to applications using
iBATIS. Basically the only thing you need to do is adding a transaction
manager to you application context and declaratively set your transaction boundaries using
for example the TransactionProxyFactoryBean. More on this can be found
in
|
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[4]/para[2] |
| Original | Traduction |
TODO elaborate!
|
|
| |
| |
|