From 62406474e0e4569d427cdd4eb1d5225b6d6c1e50 Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Fri, 22 May 2009 16:16:12 +0000 Subject: [PATCH] first cut at re-organizing the ORM chapter; moved outdated sections to new Classic Spring Usage appendix --- .../src/classic-spring.xml | 430 ++++++ spring-framework-reference/src/orm.xml | 1362 ++++++----------- .../src/spring-framework-reference.xml | 1 + 3 files changed, 924 insertions(+), 869 deletions(-) create mode 100644 spring-framework-reference/src/classic-spring.xml diff --git a/spring-framework-reference/src/classic-spring.xml b/spring-framework-reference/src/classic-spring.xml new file mode 100644 index 00000000000..27f41258bdd --- /dev/null +++ b/spring-framework-reference/src/classic-spring.xml @@ -0,0 +1,430 @@ + + + + Classic Spring Usage + + 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. + +
+ Classic ORM usage + + 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 chapter. + + +
+ Hibernate + + For the currently recommended usage patterns for Hibernate see + + +
+ The <classname>HibernateTemplate</classname> + + 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 + SessionFactory. It can get the latter + from anywhere, but preferably as bean reference from a Spring IoC + container - via a simple + setSessionFactory(..) bean property setter. + The following snippets show a DAO definition in a Spring container, + referencing the above defined + SessionFactory, and an example for a + DAO method implementation. + + <beans> + + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="sessionFactory" ref="mySessionFactory"/> + </bean> + +</beans> + + 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); + } +} + + The HibernateTemplate class provides many + methods that mirror the methods exposed on the Hibernate + Session interface, in addition to a + number of convenience methods such as the one shown above. If you need + access to the Session to invoke methods + that are not exposed on the HibernateTemplate, + you can always drop down to a callback-based approach like so. + + 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(); + } + }; + } +} + + A callback implementation effectively can be used for any + Hibernate data access. HibernateTemplate will + ensure that Session 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, 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: + + 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); + } +} +
+ +
+ Implementing Spring-based DAOs without callbacks + + As alternative to using Spring's + HibernateTemplate 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 + DataAccessException hierarchy. The + HibernateDaoSupport base class offers methods + to access the current transactional + Session and to convert exceptions in + such a scenario; similar methods are also available as static helpers + on the SessionFactoryUtils class. Note that + such code will usually pass 'false' as the value of + the getSession(..) methods + 'allowCreate' argument, to enforce running within a + transaction (which avoids the need to close the returned + Session, as its lifecycle is managed by + the transaction). + + 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); + } + } +} + + The advantage of such direct Hibernate access code is that it + allows any checked application exception to be + thrown within the data access code; contrast this to the + HibernateTemplate 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 HibernateTemplate. In general, the + HibernateTemplate class' convenience methods + are simpler and more convenient for many scenarios. +
+
+ +
+ JPA + + For the currently recommended usage patterns for JPA see + +
+ <classname>JpaTemplate</classname> and + <classname>JpaDaoSupport</classname> + + Each JPA-based DAO will then receive a + EntityManagerFactory via dependency + injection. Such a DAO can be coded against plain JPA and work with the + given EntityManagerFactory or through + Spring's JpaTemplate: + + <beans> + + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="entityManagerFactory" ref="myEmf"/> + </bean> + +</beans> + + 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(); + // do some further processing with the result list + return result; + } + }); + } +} + + The JpaCallback implementation + allows any type of JPA data access. The + JpaTemplate will ensure that + EntityManagers are properly opened and + closed and automatically participate in transactions. Moreover, the + JpaTemplate 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 + JpaTemplate offers single-step actions such as + find, load, merge, etc along with alternative convenience methods that + can replace one line callback implementations. + + Furthermore, Spring provides a convenient + JpaDaoSupport base class that provides the + get/setEntityManagerFactory and + getJpaTemplate() to be used by + subclasses: + + public class ProductDaoImpl extends JpaDaoSupport implements ProductDao { + + public Collection loadProductsByCategory(String category) throws DataAccessException { + Map<String, String> params = new HashMap<String, String>(); + params.put("category", category); + return getJpaTemplate().findByNamedParams("from Product as p where p.category = :category", params); + } +} + + Besides working with Spring's + JpaTemplate, one can also code Spring-based + DAOs against the JPA, doing one's own explicit + EntityManager 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. JpaDaoSupport offers a + variety of support methods for this scenario, for retrieving and + releasing a transaction EntityManager, + as well as for converting exceptions. + + JpaTemplate mainly exists as a sibling of JdoTemplate + and HibernateTemplate, offering the same style for people used to + it. +
+
+ +
+ JDO + + For the currently recommended usage patterns for JDO see + +
+ <classname>JdoTemplate</classname> and + <classname>JdoDaoSupport</classname> + + Each JDO-based DAO will then receive the + PersistenceManagerFactory through + dependency injection. Such a DAO could be coded against plain JDO API, + working with the given + PersistenceManagerFactory, but will + usually rather be used with the Spring Framework's + JdoTemplate: + + <beans> + + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="persistenceManagerFactory" ref="myPmf"/> + </bean> + +</beans> + + 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); + // do some further stuff with the result list + return result; + } + }); + } +} + + A callback implementation can effectively be used for any JDO + data access. JdoTemplate will ensure that + PersistenceManagers 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 find, + load, makePersistent, or + delete call, JdoTemplate + offers alternative convenience methods that can replace such one line + callback implementations. Furthermore, Spring provides a convenient + JdoDaoSupport base class that provides a + setPersistenceManagerFactory(..) method for + receiving a PersistenceManagerFactory, and + getPersistenceManagerFactory() and + getJdoTemplate() for use by subclasses. In + combination, this allows for very simple DAO implementations for + typical requirements: + + 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}); + } +} + + As alternative to working with Spring's + JdoTemplate, you can also code Spring-based + DAOs at the JDO API level, explicitly opening and closing a + PersistenceManager. 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. JdoDaoSupport offers a variety of + support methods for this scenario, for fetching and releasing a + transactional PersistenceManager as + well as for converting exceptions. +
+
+ +
+ iBATIS + + For the currently recommended usage patterns for iBATIS see + +
+ Using <classname>SqlMapClientTemplate</classname> and + <classname>SqlMapClientDaoSupport</classname> + + The SqlMapClientDaoSupport class offers a + supporting class similar to the + SqlMapDaoSupport. We extend it to implement our + DAO: + + 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); + } +} + + In the DAO, we use the pre-configured + SqlMapClientTemplate to execute the queries, + after setting up the SqlMapAccountDao in the + application context and wiring it with our + SqlMapClient instance: + + <beans> + + <bean id="accountDao" class="example.SqlMapAccountDao"> + <property name="sqlMapClient" ref="sqlMapClient"/> + </bean> + +</beans> + + Note that a SqlMapTemplate instance could + also be created manually, passing in the + SqlMapClient as constructor argument. The + SqlMapClientDaoSupport base class simply + pre-initializes a SqlMapClientTemplate instance + for us. + + The SqlMapClientTemplate also offers a + generic execute method, taking a custom + SqlMapClientCallback implementation as argument. + This can, for example, be used for batching: + + 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(); + } + }); + } +} + + In general, any combination of operations offered by the native + SqlMapExecutor API can be used in such a callback. + Any SQLException thrown will automatically get + converted to Spring's generic + DataAccessException hierarchy. +
+
+
+ +
+ Classic Spring MVC + + ... +
+
diff --git a/spring-framework-reference/src/orm.xml b/spring-framework-reference/src/orm.xml index a8525fa5723..4a55059f74c 100644 --- a/spring-framework-reference/src/orm.xml +++ b/spring-framework-reference/src/orm.xml @@ -238,150 +238,6 @@ However, that is typically not common outside of an EJB context. -
- The <classname>HibernateTemplate</classname> - - 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 - SessionFactory. It can get the latter - from anywhere, but preferably as bean reference from a Spring IoC - container - via a simple setSessionFactory(..) - bean property setter. The following snippets show a DAO definition in a - Spring container, referencing the above defined - SessionFactory, and an example for a DAO - method implementation. - - <beans> - - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="sessionFactory" ref="mySessionFactory"/> - </bean> - -</beans> - - 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); - } -} - - The HibernateTemplate class provides many - methods that mirror the methods exposed on the Hibernate - Session interface, in addition to a - number of convenience methods such as the one shown above. If you need - access to the Session to invoke methods - that are not exposed on the HibernateTemplate, - you can always drop down to a callback-based approach like so. - - 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(); - } - }; - } -} - - A callback implementation effectively can be used for any - Hibernate data access. HibernateTemplate will - ensure that Session 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, 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: - - 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); - } -} -
- -
- Implementing Spring-based DAOs without callbacks - - As alternative to using Spring's - HibernateTemplate 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 - DataAccessException hierarchy. The - HibernateDaoSupport base class offers methods to - access the current transactional Session - and to convert exceptions in such a scenario; similar methods are also - available as static helpers on the - SessionFactoryUtils class. Note that such code - will usually pass 'false' as the value of the - getSession(..) methods - 'allowCreate' argument, to enforce running within a - transaction (which avoids the need to close the returned - Session, as its lifecycle is managed by - the transaction). - - 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); - } - } -} - - The advantage of such direct Hibernate access code is that it - allows any checked application exception to be - thrown within the data access code; contrast this to the - HibernateTemplate 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 - HibernateTemplate. In general, the - HibernateTemplate class' convenience methods are - simpler and more convenient for many scenarios. -
-
Implementing DAOs based on plain Hibernate 3 API @@ -950,608 +806,6 @@
-
- JDO - - 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 - org.springframework.orm.jdo package. - -
- <interfacename>PersistenceManagerFactory</interfacename> - setup - - Spring provides a - LocalPersistenceManagerFactoryBean class that - allows for defining a local JDO - PersistenceManagerFactory within a Spring - application context: - - <beans> - - <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"> - <property name="configLocation" value="classpath:kodo.properties"/> - </bean> - -</beans> - - Alternatively, a - PersistenceManagerFactory can also be set - up through direct instantiation of a - PersistenceManagerFactory implementation - class. A JDO PersistenceManagerFactory - implementation class is supposed to follow the JavaBeans pattern, just - like a JDBC DataSource implementation - class, which is a natural fit for a Spring bean definition. This setup - style usually supports a Spring-defined JDBC - DataSource, passed into the - "connectionFactory" property. For example, for the open source JDO - implementation JPOX (): - - <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.jpox.PersistenceManagerFactoryImpl" destroy-method="close"> - <property name="connectionFactory" ref="dataSource"/> - <property name="nontransactionalRead" value="true"/> - </bean> - -</beans> - - A JDO PersistenceManagerFactory 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 - JndiObjectFactoryBean can be used to retrieve and - expose such a PersistenceManagerFactory. - However, outside an EJB context, there is often no compelling benefit in - holding the PersistenceManagerFactory 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. -
- -
- <classname>JdoTemplate</classname> and - <classname>JdoDaoSupport</classname> - - Each JDO-based DAO will then receive the - PersistenceManagerFactory through - dependency injection. Such a DAO could be coded against plain JDO API, - working with the given - PersistenceManagerFactory, but will - usually rather be used with the Spring Framework's - JdoTemplate: - - <beans> - - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="persistenceManagerFactory" ref="myPmf"/> - </bean> - -</beans> - - 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); - // do some further stuff with the result list - return result; - } - }); - } -} - - A callback implementation can effectively be used for any JDO data - access. JdoTemplate will ensure that - PersistenceManagers 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 find, - load, makePersistent, or - delete call, JdoTemplate - offers alternative convenience methods that can replace such one line - callback implementations. Furthermore, Spring provides a convenient - JdoDaoSupport base class that provides a - setPersistenceManagerFactory(..) method for receiving - a PersistenceManagerFactory, and - getPersistenceManagerFactory() and - getJdoTemplate() for use by subclasses. In - combination, this allows for very simple DAO implementations for typical - requirements: - - 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}); - } -} - - As alternative to working with Spring's - JdoTemplate, you can also code Spring-based DAOs - at the JDO API level, explicitly opening and closing a - PersistenceManager. 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. - JdoDaoSupport offers a variety of support methods - for this scenario, for fetching and releasing a transactional - PersistenceManager as well as for - converting exceptions. -
- -
- Implementing DAOs based on the plain JDO API - - DAOs can also be written against plain JDO API, without any Spring - dependencies, directly using an injected - PersistenceManagerFactory. A - corresponding DAO implementation looks like as follows: - - 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(); - } - } -} - - 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 JdoTemplate: - - <beans> - - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="persistenceManagerFactory" ref="myPmf"/> - </bean> - -</beans> - - The main issue with such DAOs is that they always get a new - PersistenceManager from the factory. To - still access a Spring-managed transactional - PersistenceManager, consider defining a - TransactionAwarePersistenceManagerFactoryProxy - (as included in Spring) in front of your target - PersistenceManagerFactory, passing the - proxy into your DAOs. - - <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> - - Your data access code will then receive a transactional - PersistenceManager (if any) from the - PersistenceManagerFactory.getPersistenceManager() - method that it calls. The latter method call goes through the proxy, - which will first check for a current transactional - PersistenceManager before getting a new - one from the factory. close() calls on the - PersistenceManager will be ignored in - case of a transactional - PersistenceManager. - - 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 PersistenceManager.close() - call and thus the entire finally block, which you - might prefer to keep your DAO implementations concise: - - 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); - } -} - - With such DAOs that rely on active transactions, it is recommended - to enforce active transactions through turning - TransactionAwarePersistenceManagerFactoryProxy's - "allowCreate" flag off: - - <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> - - 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. - - However, the DAO throws plain - JDOException (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. - - 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 - JDOException; conversion to Spring's - DataAccessException would have to happen - explicitly (if desired). -
- -
- Transaction management - - To execute service operations within transactions, you can use - Spring's common declarative transaction facilities. For example: - - <?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> - - 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 - JdoTransactionManager, but it is necessary for - participating in JTA transactions (whether driven by Spring's - JtaTransactionManager or by EJB CMT / plain - JTA). - - JdoTransactionManager is capable of - exposing a JDO transaction to JDBC access code that accesses the same - JDBC DataSource, provided that the - registered JdoDialect supports retrieval of the - underlying JDBC Connection. This is the - case for JDBC-based JDO 2.0 implementations by default. -
- -
- <interfacename>JdoDialect</interfacename> - - As an advanced feature, both JdoTemplate - and interfacename support a custom - JdoDialect, to be passed into the - "jdoDialect" bean property. In such a scenario, the DAOs won't receive a - PersistenceManagerFactory reference but - rather a full JdoTemplate instance instead (for - example, passed into JdoDaoSupport's - "jdoTemplate" property). A JdoDialect - implementation can enable some advanced features supported by Spring, - usually in a vendor-specific manner: - - - - applying specific transaction semantics (such as custom - isolation level or transaction timeout) - - - - retrieving the transactional JDBC - Connection (for exposure to - JDBC-based DAOs) - - - - applying query timeouts (automatically calculated from - Spring-managed transaction timeout) - - - - eagerly flushing a - PersistenceManager (to make - transactional changes visible to JDBC-based data access code) - - - - advanced translation of JDOExceptions to - Spring DataAccessExceptions - - - - See the JdoDialect Javadoc for more details - on its operations and how they are used within Spring's JDO - support. -
-
- -
- iBATIS SQL Maps - - The iBATIS support in the Spring Framework much resembles the JDBC / - Hibernate support in that it supports the same template style programming - and just as with JDBC or Hibernate, the iBATIS support works with Spring's - exception hierarchy and let's you enjoy the all IoC features Spring - has. - - 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 - Connection. Hence, Spring's standard JDBC - DataSourceTransactionManager or - JtaTransactionManager are perfectly - sufficient. - - - Spring does actually support both iBatis 1.x and 2.x. However, - only support for iBatis 2.x is actually shipped with the core Spring - distribution. 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. - - -
- Setting up the <classname>SqlMapClient</classname> - - If we want to map the previous Account class with iBATIS 2.x we - need to create the following SQL map - 'Account.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> - - The configuration file for iBATIS 2 looks like this: - - <sqlMapConfig> - - <sqlMap resource="example/Account.xml"/> - -</sqlMapConfig> - - Remember that iBATIS loads resources from the class path, so be - sure to add the 'Account.xml' file to the class - path. - - We can use the SqlMapClientFactoryBean in - the Spring container. Note that with iBATIS SQL Maps 2.x, the JDBC - DataSource is usually specified on the - SqlMapClientFactoryBean, which enables lazy - loading. - - <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> -
- -
- Using <classname>SqlMapClientTemplate</classname> and - <classname>SqlMapClientDaoSupport</classname> - - The SqlMapClientDaoSupport class offers a - supporting class similar to the SqlMapDaoSupport. - We extend it to implement our DAO: - - 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); - } -} - - In the DAO, we use the pre-configured - SqlMapClientTemplate to execute the queries, - after setting up the SqlMapAccountDao in the - application context and wiring it with our - SqlMapClient instance: - - <beans> - - <bean id="accountDao" class="example.SqlMapAccountDao"> - <property name="sqlMapClient" ref="sqlMapClient"/> - </bean> - -</beans> - - Note that a SqlMapTemplate instance could - also be created manually, passing in the SqlMapClient - as constructor argument. The SqlMapClientDaoSupport - base class simply pre-initializes a - SqlMapClientTemplate instance for us. - - The SqlMapClientTemplate also offers a - generic execute method, taking a custom - SqlMapClientCallback implementation as argument. This - can, for example, be used for batching: - - 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(); - } - }); - } -} - - In general, any combination of operations offered by the native - SqlMapExecutor API can be used in such a callback. - Any SQLException thrown will automatically get - converted to Spring's generic DataAccessException - hierarchy. -
- -
- Implementing DAOs based on plain iBATIS API - - DAOs can also be written against plain iBATIS API, without any - Spring dependencies, directly using an injected - SqlMapClient. A corresponding DAO implementation - looks like as follows: - - 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); - } - } -} - - In such a scenario, the SQLException 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: - - <beans> - - <bean id="accountDao" class="example.SqlMapAccountDao"> - <property name="sqlMapClient" ref="sqlMapClient"/> - </bean> - -</beans> -
-
-
JPA @@ -2000,93 +1254,6 @@
-
- <classname>JpaTemplate</classname> and - <classname>JpaDaoSupport</classname> - - Each JPA-based DAO will then receive a - EntityManagerFactory via dependency - injection. Such a DAO can be coded against plain JPA and work with the - given EntityManagerFactory or through - Spring's JpaTemplate: - - <beans> - - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="entityManagerFactory" ref="myEmf"/> - </bean> - -</beans> - - 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(); - // do some further processing with the result list - return result; - } - }); - } -} - - The JpaCallback implementation - allows any type of JPA data access. The - JpaTemplate will ensure that - EntityManagers are properly opened and - closed and automatically participate in transactions. Moreover, the - JpaTemplate 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 - JpaTemplate offers single-step actions such as - find, load, merge, etc along with alternative convenience methods that - can replace one line callback implementations. - - Furthermore, Spring provides a convenient - JpaDaoSupport base class that provides the - get/setEntityManagerFactory and - getJpaTemplate() to be used by - subclasses: - - public class ProductDaoImpl extends JpaDaoSupport implements ProductDao { - - public Collection loadProductsByCategory(String category) throws DataAccessException { - Map<String, String> params = new HashMap<String, String>(); - params.put("category", category); - return getJpaTemplate().findByNamedParams("from Product as p where p.category = :category", params); - } -} - - Besides working with Spring's JpaTemplate, - one can also code Spring-based DAOs against the JPA, doing one's own - explicit EntityManager 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. JpaDaoSupport offers a variety of - support methods for this scenario, for retrieving and releasing a - transaction EntityManager, as well as for - converting exceptions. - - JpaTemplate mainly exists as a sibling of JdoTemplate - and HibernateTemplate, offering the same style for people used to it. - For newly started projects, consider adopting the native JPA style of - coding data access objects instead, based on a "shared EntityManager" - reference obtained through the JPA - @PersistenceContext annotation (using Spring's - PersistenceAnnotationBeanPostProcessor; see below - for details.) -
-
Implementing DAOs based on plain JPA @@ -2286,6 +1453,50 @@ public class ProductDaoImpl implements ProductDao {
+
+ <interfacename>JpaDialect</interfacename> + + As an advanced feature JpaTemplate, + JpaTransactionManager and subclasses of + AbstractEntityManagerFactoryBean support a custom + JpaDialect, to be passed into the + "jpaDialect" bean property. In such a scenario, the DAOs won't receive an + EntityManagerFactory reference but rather a + full JpaTemplate instance instead (for example, + passed into JpaDaoSupport's "jpaTemplate" + property). A JpaDialect implementation can + enable some advanced features supported by Spring, usually in a + vendor-specific manner: + + + + applying specific transaction semantics (such as custom + isolation level or transaction timeout) + + + + retrieving the transactional JDBC + Connection (for exposure to JDBC-based + DAOs) + + + + advanced translation of PersistenceExceptions + to Spring DataAccessExceptions + + + + This is particularly valuable for special transaction semantics and + for advanced translation of exception. Note that the default + implementation used (DefaultJpaDialect) doesn't + provide any special capabilities and if the above features are required, + the appropriate dialect has to be specified. + + See the JpaDialect Javadoc for more + details of its operations and how they are used within Spring's JPA + support. +
+
Transaction Management @@ -2339,47 +1550,460 @@ public class ProductDaoImpl implements ProductDao { JpaDialect mechanism.
-
- <interfacename>JpaDialect</interfacename> +
+ JDO - As an advanced feature JpaTemplate, - JpaTransactionManager and subclasses of - AbstractEntityManagerFactoryBean support a custom - JpaDialect, to be passed into the - "jpaDialect" bean property. In such a scenario, the DAOs won't receive an - EntityManagerFactory reference but rather a - full JpaTemplate instance instead (for example, - passed into JpaDaoSupport's "jpaTemplate" - property). A JpaDialect implementation can - enable some advanced features supported by Spring, usually in a - vendor-specific manner: + 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 + org.springframework.orm.jdo package. - - - applying specific transaction semantics (such as custom - isolation level or transaction timeout) - +
+ <interfacename>PersistenceManagerFactory</interfacename> + setup - - retrieving the transactional JDBC - Connection (for exposure to JDBC-based - DAOs) - + Spring provides a + LocalPersistenceManagerFactoryBean class that + allows for defining a local JDO + PersistenceManagerFactory within a Spring + application context: - - advanced translation of PersistenceExceptions - to Spring DataAccessExceptions - - + <beans> - This is particularly valuable for special transaction semantics and - for advanced translation of exception. Note that the default - implementation used (DefaultJpaDialect) doesn't - provide any special capabilities and if the above features are required, - the appropriate dialect has to be specified. + <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"> + <property name="configLocation" value="classpath:kodo.properties"/> + </bean> - See the JpaDialect Javadoc for more - details of its operations and how they are used within Spring's JPA - support. +</beans> + + Alternatively, a + PersistenceManagerFactory can also be set + up through direct instantiation of a + PersistenceManagerFactory implementation + class. A JDO PersistenceManagerFactory + implementation class is supposed to follow the JavaBeans pattern, just + like a JDBC DataSource implementation + class, which is a natural fit for a Spring bean definition. This setup + style usually supports a Spring-defined JDBC + DataSource, passed into the + "connectionFactory" property. For example, for the open source JDO + implementation JPOX (): + + <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.jpox.PersistenceManagerFactoryImpl" destroy-method="close"> + <property name="connectionFactory" ref="dataSource"/> + <property name="nontransactionalRead" value="true"/> + </bean> + +</beans> + + A JDO PersistenceManagerFactory 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 + JndiObjectFactoryBean can be used to retrieve and + expose such a PersistenceManagerFactory. + However, outside an EJB context, there is often no compelling benefit in + holding the PersistenceManagerFactory 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. +
+ +
+ Implementing DAOs based on the plain JDO API + + DAOs can also be written against plain JDO API, without any Spring + dependencies, directly using an injected + PersistenceManagerFactory. A + corresponding DAO implementation looks like as follows: + + 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(); + } + } +} + + 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 JdoTemplate: + + <beans> + + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="persistenceManagerFactory" ref="myPmf"/> + </bean> + +</beans> + + The main issue with such DAOs is that they always get a new + PersistenceManager from the factory. To + still access a Spring-managed transactional + PersistenceManager, consider defining a + TransactionAwarePersistenceManagerFactoryProxy + (as included in Spring) in front of your target + PersistenceManagerFactory, passing the + proxy into your DAOs. + + <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> + + Your data access code will then receive a transactional + PersistenceManager (if any) from the + PersistenceManagerFactory.getPersistenceManager() + method that it calls. The latter method call goes through the proxy, + which will first check for a current transactional + PersistenceManager before getting a new + one from the factory. close() calls on the + PersistenceManager will be ignored in + case of a transactional + PersistenceManager. + + 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 PersistenceManager.close() + call and thus the entire finally block, which you + might prefer to keep your DAO implementations concise: + + 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); + } +} + + With such DAOs that rely on active transactions, it is recommended + to enforce active transactions through turning + TransactionAwarePersistenceManagerFactoryProxy's + "allowCreate" flag off: + + <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> + + 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. + + However, the DAO throws plain + JDOException (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. + + 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 + JDOException; conversion to Spring's + DataAccessException would have to happen + explicitly (if desired). +
+ +
+ Transaction management + + To execute service operations within transactions, you can use + Spring's common declarative transaction facilities. For example: + + <?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> + + 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 + JdoTransactionManager, but it is necessary for + participating in JTA transactions (whether driven by Spring's + JtaTransactionManager or by EJB CMT / plain + JTA). + + JdoTransactionManager is capable of + exposing a JDO transaction to JDBC access code that accesses the same + JDBC DataSource, provided that the + registered JdoDialect supports retrieval of the + underlying JDBC Connection. This is the + case for JDBC-based JDO 2.0 implementations by default. +
+ +
+ <interfacename>JdoDialect</interfacename> + + As an advanced feature, both JdoTemplate + and interfacename support a custom + JdoDialect, to be passed into the + "jdoDialect" bean property. In such a scenario, the DAOs won't receive a + PersistenceManagerFactory reference but + rather a full JdoTemplate instance instead (for + example, passed into JdoDaoSupport's + "jdoTemplate" property). A JdoDialect + implementation can enable some advanced features supported by Spring, + usually in a vendor-specific manner: + + + + applying specific transaction semantics (such as custom + isolation level or transaction timeout) + + + + retrieving the transactional JDBC + Connection (for exposure to + JDBC-based DAOs) + + + + applying query timeouts (automatically calculated from + Spring-managed transaction timeout) + + + + eagerly flushing a + PersistenceManager (to make + transactional changes visible to JDBC-based data access code) + + + + advanced translation of JDOExceptions to + Spring DataAccessExceptions + + + + See the JdoDialect Javadoc for more details + on its operations and how they are used within Spring's JDO + support. +
+
+ +
+ iBATIS SQL Maps + + The iBATIS support in the Spring Framework much resembles the JDBC / + Hibernate support in that it supports the same template style programming + and just as with JDBC or Hibernate, the iBATIS support works with Spring's + exception hierarchy and let's you enjoy the all IoC features Spring + has. + + 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 + Connection. Hence, Spring's standard JDBC + DataSourceTransactionManager or + JtaTransactionManager are perfectly + sufficient. + + + Spring does actually support both iBatis 1.x and 2.x. However, + only support for iBatis 2.x is actually shipped with the core Spring + distribution. 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. + + +
+ Setting up the <classname>SqlMapClient</classname> + + If we want to map the previous Account class with iBATIS 2.x we + need to create the following SQL map + 'Account.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> + + The configuration file for iBATIS 2 looks like this: + + <sqlMapConfig> + + <sqlMap resource="example/Account.xml"/> + +</sqlMapConfig> + + Remember that iBATIS loads resources from the class path, so be + sure to add the 'Account.xml' file to the class + path. + + We can use the SqlMapClientFactoryBean in + the Spring container. Note that with iBATIS SQL Maps 2.x, the JDBC + DataSource is usually specified on the + SqlMapClientFactoryBean, which enables lazy + loading. + + <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> +
+ +
+ Implementing DAOs based on plain iBATIS API + + DAOs can also be written against plain iBATIS API, without any + Spring dependencies, directly using an injected + SqlMapClient. A corresponding DAO implementation + looks like as follows: + + 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); + } + } +} + + In such a scenario, the SQLException 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: + + <beans> + + <bean id="accountDao" class="example.SqlMapAccountDao"> + <property name="sqlMapClient" ref="sqlMapClient"/> + </bean> + +</beans> +
diff --git a/spring-framework-reference/src/spring-framework-reference.xml b/spring-framework-reference/src/spring-framework-reference.xml index f9c3e49ea7e..9b18161341a 100644 --- a/spring-framework-reference/src/spring-framework-reference.xml +++ b/spring-framework-reference/src/spring-framework-reference.xml @@ -330,6 +330,7 @@ +