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,1436 +806,1204 @@
-
- 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: +
+ JPA - <beans> + Spring JPA (available under the + org.springframework.orm.jpa package) offers + comprehensive support for the Java + Persistence API in a similar manner to the integration with + Hibernate or JDO, while being aware of the underlying implementation in + order to provide additional features. - <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"> - <property name="configLocation" value="classpath:kodo.properties"/> - </bean> +
+ JPA setup in a Spring environment -</beans> + Spring JPA offers three ways of setting up JPA + EntityManagerFactory: - 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 (): +
+ <classname>LocalEntityManagerFactoryBean</classname> - <beans> + The LocalEntityManagerFactoryBean creates + an EntityManagerFactory suitable for + environments which solely use JPA for data access. The factory bean + will use the JPA PersistenceProvider + autodetection mechanism (according to JPA's Java SE bootstrapping) + and, in most cases, requires only the persistence unit name to be + specified: - <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> + <beans> - <bean id="myPmf" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close"> - <property name="connectionFactory" ref="dataSource"/> - <property name="nontransactionalRead" value="true"/> - </bean> + <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> + <property name="persistenceUnitName" value="myPersistenceUnit"/> + </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. -
+ This is the simplest but also most limited form of JPA + deployment. There is no way to link to an existing JDBC + DataSource and no support for global + transactions, for example. Furthermore, weaving (byte-code + transformation) of persistent classes is provider-specific, often + requiring a specific JVM agent to specified on startup. All in all, + this option is only really sufficient for standalone applications and + test environments (which is exactly what the JPA specification + designed it for). -
- <classname>JdoTemplate</classname> and - <classname>JdoDaoSupport</classname> + Only use this option in simple deployment environments + like standalone applications and integration tests. +
- 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: +
+ <classname>Obtaining an EntityManagerFactory from + JNDI</classname> - <beans> - - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="persistenceManagerFactory" ref="myPmf"/> - </bean> - -</beans> + Obtaining an EntityManagerFactory + from JNDI (for example in a Java EE 5 environment), is just a matter + of changing the XML configuration: - public class ProductDaoImpl implements ProductDao { - - private JdoTemplate jdoTemplate; + <beans> - public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { - this.jdoTemplate = new JdoTemplate(pmf); - } + <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> - 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; - } - }); - } -} +</beans> - 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}); - } -} + This assumes standard Java EE 5 bootstrapping, with the Java EE + server autodetecting persistence units (i.e. + META-INF/persistence.xml files in application jars) + and persistence-unit-ref entries in the Java EE + deployment descriptor (e.g. web.xml) defining + environment naming context locations for those persistence + units. - 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. -
+ In such a scenario, the entire persistence unit deployment, + including the weaving (byte-code transformation) of persistent + classes, is up to the Java EE server. The JDBC + DataSource is defined through a JNDI + location in the META-INF/persistence.xml file; + EntityManager transactions are integrated with the server's JTA + subsystem. Spring merely uses the obtained + EntityManagerFactory, passing it on to + application objects via dependency injection, and managing + transactions for it (typically through + JtaTransactionManager). -
- Implementing DAOs based on the plain JDO API + Note that, in case of multiple persistence units used in the + same application, the bean names of such a JNDI-retrieved persistence + units should match the persistence unit names that the application + uses to refer to them (e.g. in @PersistenceUnit and + @PersistenceContext annotations). - 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: + Use this option when deploying to a Java EE 5 server. + Check your server's documentation on how to deploy a custom JPA + provider into your server, allowing for a different provider than the + server's default. +
- public class ProductDaoImpl implements ProductDao { +
+ <classname>LocalContainerEntityManagerFactoryBean</classname> - private PersistenceManagerFactory persistenceManagerFactory; + The + LocalContainerEntityManagerFactoryBean gives + full control over EntityManagerFactory + configuration and is appropriate for environments where fine-grained + customization is required. The + LocalContainerEntityManagerFactoryBean will + create a PersistenceUnitInfo based on + the persistence.xml file, the supplied + dataSourceLookup strategy and the specified + loadTimeWeaver. It is thus possible to work with + custom DataSources outside of JNDI and to control the weaving + process. - public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { - this.persistenceManagerFactory = pmf; - } + <beans> + + <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> + <property name="dataSource" ref="someDataSource"/> + <property name="loadTimeWeaver"> + <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> + </property> + </bean> + +</beans> - 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(); - } - } -} + A typical persistence.xml file looks as + follows: - 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: + <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> - <beans> + <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL"> + <mapping-file>META-INF/orm.xml</mapping-file> + <exclude-unlisted-classes/> + </persistence-unit> - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="persistenceManagerFactory" ref="myPmf"/> - </bean> +</persistence> -</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. + NOTE: The "exclude-unlisted-classes" element always + indicates that NO scanning for annotated entity classes is supposed to + happen, in order to support the + <exclude-unlisted-classes/> shortcut. This is + in line with the JPA specification (which suggests that shortcut) but + unfortunately in conflict with the JPA XSD (which implies "false" for + that shortcut). As a consequence, + "<exclude-unlisted-classes> false + </exclude-unlisted-classes/>" is not supported! Simply + omit the "exclude-unlisted-classes" element if you would like entity + class scanning to actually happen. - <beans> + This is the most powerful JPA setup option, allowing for + flexible local configuration within the application. It supports links + to an existing JDBC DataSource, + supports both local and global transactions, etc. However, it also + imposes requirements onto the runtime environment, such as the + availability of a weaving-capable ClassLoader if the persistence + provider demands byte-code transformation. - <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> + Note that this option may conflict with the built-in JPA + capabilities of a Java EE 5 server. So when running in a full Java EE + 5 environment, consider obtaining your + EntityManagerFactory from JNDI. + Alternatively, specify a custom "persistenceXmlLocation" on your + LocalContainerEntityManagerFactoryBean + definition, e.g. "META-INF/my-persistence.xml", and only include a + descriptor with that name in your application jar files. Since the + Java EE 5 server will only look for default + META-INF/persistence.xml files, it will ignore such + custom persistence units and hence avoid conflicts with a + Spring-driven JPA setup upfront. (This applies to Resin 3.1, for + example.) - <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> - <property name="configLocation" value="WEB-INF/sqlmap-config.xml"/> - <property name="dataSource" ref="dataSource"/> - </bean> + Use this option for full JPA capabilities in a + Spring-based application environment. This includes web containers + such as Tomcat as well as standalone applications and integration + tests with sophisticated persistence requirements. -</beans> -
+ + When is load-time weaving required? -
- Using <classname>SqlMapClientTemplate</classname> and - <classname>SqlMapClientDaoSupport</classname> + Not all JPA providers impose the need of a JVM agent + (Hibernate being an example). If your provider does not require an + agent or you have other alternatives (for example applying + enhancements at build time through a custom compiler or an ant task) + the load-time weaver should not be + used. + - The SqlMapClientDaoSupport class offers a - supporting class similar to the SqlMapDaoSupport. - We extend it to implement our DAO: + The LoadTimeWeaver interface is a + Spring-provided class that allows JPA + ClassTransformer instances to be + plugged in a specific manner depending on the environment (web + container/application server). Hooking + ClassTransformers through a Java 5 agent + is typically not efficient - the agents work against the + entire virtual machine and inspect + every class that is loaded - something that is + typically undesirable in a production server enviroment. - public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao { + Spring provides a number of + LoadTimeWeaver implementations for + various environments, allowing + ClassTransformer instances to be + applied only per ClassLoader and not per + VM. - public Account getAccount(String email) throws DataAccessException { - return (Account) getSqlMapClientTemplate().queryForObject("getAccountByEmail", email); - } + The following sections will discuss typical JPA weaving setup on + Tomcat as well as using Spring's VM agent. See the AOP chapter section + entitled for details on how to + set up general load-time weaving, covering Tomcat and the VM agent as + well as WebLogic, OC4J, GlassFish and Resin. - public void insertAccount(Account account) throws DataAccessException { - getSqlMapClientTemplate().update("insertAccount", account); - } -} +
+ Tomcat load-time weaving setup (5.0+) - 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: + Apache Tomcat's + default ClassLoader does not support class transformation but allows + custom ClassLoaders to be used. Spring offers the + TomcatInstrumentableClassLoader (inside the + org.springframework.instrument.classloading.tomcat + package) which extends the Tomcat ClassLoader + (WebappClassLoader) and allows JPA + ClassTransformer instances to 'enhance' all + classes loaded by it. In short, JPA transformers will be applied + only inside a specific web application (which uses the + TomcatInstrumentableClassLoader). - <beans> + In order to use the custom ClassLoader on: - <bean id="accountDao" class="example.SqlMapAccountDao"> - <property name="sqlMapClient" ref="sqlMapClient"/> - </bean> + + + Tomcat 5.0.x/5.5.x + -</beans> + + + Copy spring-tomcat-weaver.jar into + $CATALINA_HOME/server/lib (where + $CATALINA_HOME represents the root of the + Tomcat installation). + - 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. + + Instruct Tomcat to use the custom ClassLoader (instead + of the default one) by editing the web application context + file: - The SqlMapClientTemplate also offers a - generic execute method, taking a custom - SqlMapClientCallback implementation as argument. This - can, for example, be used for batching: + <Context path="/myWebApp" docBase="/my/webApp/location"> + <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> +</Context> - public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao { + Tomcat 5.0.x and 5.5.x series support several context + locations: server configuration file + ($CATALINA_HOME/conf/server.xml), the + default context configuration + ($CATALINA_HOME/conf/context.xml) that + affects all deployed web applications and per-webapp + configurations, deployed on the server + ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) + side or along with the webapp + (your-webapp.war/META-INF/context.xml). + For efficiency, inside the web-app configuration style is + recommended since only applications which use JPA will use the + custom ClassLoader. See the Tomcat 5.x documentation + for more details about available context locations. - 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(); - } - }); - } -} + Note that versions prior to 5.5.20 contained a bug in + the XML configuration parsing preventing usage of + Loader tag inside + server.xml (no matter if a ClassLoader is + specified or not (be it the official or a custom one). See + Tomcat's bugzilla for more + details. - 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. -
+ If you are using Tomcat 5.5.20+ you can set + useSystemClassLoaderAsParent to + false to fix the problem: <Context path="/myWebApp" docBase="/my/webApp/location"> + <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" + useSystemClassLoaderAsParent="false"/> +</Context> + + -
- Implementing DAOs based on plain iBATIS API + + Tomcat 6.0.x + - 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: + + + Copy spring-tomcat-weaver.jar into + $CATALINA_HOME/lib (where + $CATALINA_HOME represents the root of the + Tomcat installation). + - public class SqlMapAccountDao implements AccountDao { - - private SqlMapClient sqlMapClient; - - public void setSqlMapClient(SqlMapClient sqlMapClient) { - this.sqlMapClient = sqlMapClient; - } + + Instruct Tomcat to use the custom ClassLoader (instead + of the default one) by editing the web application context + file: - public Account getAccount(String email) { - try { - return (Account) this.sqlMapClient.queryForObject("getAccountByEmail", email); - } - catch (SQLException ex) { - throw new MyDaoException(ex); - } - } + <Context path="/myWebApp" docBase="/my/webApp/location"> + <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> +</Context> - public void insertAccount(Account account) throws DataAccessException { - try { - this.sqlMapClient.update("insertAccount", account); - } - catch (SQLException ex) { - throw new MyDaoException(ex); - } - } -} + Tomcat 6.0.x (similar to 5.0.x/5.5.x) series support + several context locations: server configuration file + ($CATALINA_HOME/conf/server.xml), the + default context configuration + ($CATALINA_HOME/conf/context.xml) that + affects all deployed web applications and per-webapp + configurations, deployed on the server + ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) + side or along with the webapp + (your-webapp.war/META-INF/context.xml). + For efficiency, inside the web-app configuration style is + recommended since only applications which use JPA will use the + custom ClassLoader. See the Tomcat 5.x documentation + for more details about available context locations. + + + - 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: + The last step required on all Tomcat versions, is to use the + appropriate the LoadTimeWeaver when + configuring + LocalContainerEntityManagerFactoryBean: - <beans> + <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> + <property name="loadTimeWeaver"> + <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/> + </property> +</bean> - <bean id="accountDao" class="example.SqlMapAccountDao"> - <property name="sqlMapClient" ref="sqlMapClient"/> - </bean> + Using this technique, JPA applications relying on + instrumentation, can run in Tomcat without the need of an agent. + This is important especially when hosting applications which rely on + different JPA implementations since the JPA transformers are applied + only at ClassLoader level and thus, are isolated from each + other. -</beans> -
-
+ + If TopLink Essentials is being used a JPA provider under + Tomcat, please place the toplink-essentials jar under + $CATALINA_HOME/shared/lib folder instead of + your war. + +
-
- JPA +
+ General load-time weaving using the VM agent - Spring JPA (available under the - org.springframework.orm.jpa package) offers - comprehensive support for the Java - Persistence API in a similar manner to the integration with - Hibernate or JDO, while being aware of the underlying implementation in - order to provide additional features. + For environments where class instrumentation is required but + are not supported by the existing LoadTimeWeaver implementations, a + JDK agent can be the only solution. For such cases, Spring provides + InstrumentationLoadTimeWeaver which requires + a Spring-specific (but very general) VM agent (spring-agent.jar): -
- JPA setup in a Spring environment + <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> + <property name="loadTimeWeaver"> + <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> + </property> +</bean> - Spring JPA offers three ways of setting up JPA - EntityManagerFactory: + Note that the virtual machine has to be started with the + Spring agent, by supplying the following JVM options: -
- <classname>LocalEntityManagerFactoryBean</classname> + -javaagent:/path/to/spring-agent.jar +
- The LocalEntityManagerFactoryBean creates - an EntityManagerFactory suitable for - environments which solely use JPA for data access. The factory bean - will use the JPA PersistenceProvider - autodetection mechanism (according to JPA's Java SE bootstrapping) - and, in most cases, requires only the persistence unit name to be - specified: +
+ Context-wide load-time weaver setup - <beans> + Since Spring 2.5, a context-wide + LoadTimeWeaver can be configured + using the context:load-time-weaver configuration + element. Such a 'global' weaver will be picked up by all JPA + LocalContainerEntityManagerFactoryBeans + automatically. - <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> - <property name="persistenceUnitName" value="myPersistenceUnit"/> - </bean> + This is the preferred way of setting up a load-time weaver, + delivering autodetection of the platform (WebLogic, OC4J, GlassFish, + Tomcat, Resin, VM agent) as well as automatic propagation of the + weaver to all weaver-aware beans. -</beans> + <context:load-time-weaver/> - This is the simplest but also most limited form of JPA - deployment. There is no way to link to an existing JDBC - DataSource and no support for global - transactions, for example. Furthermore, weaving (byte-code - transformation) of persistent classes is provider-specific, often - requiring a specific JVM agent to specified on startup. All in all, - this option is only really sufficient for standalone applications and - test environments (which is exactly what the JPA specification - designed it for). +<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> + ... +</bean> - Only use this option in simple deployment environments - like standalone applications and integration tests. + See the section entitled + for details on how to set up general load-time weaving, covering + Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and + Resin. +
-
- <classname>Obtaining an EntityManagerFactory from - JNDI</classname> - - Obtaining an EntityManagerFactory - from JNDI (for example in a Java EE 5 environment), is just a matter - of changing the XML configuration: +
+ Dealing with multiple persistence units - <beans> + For applications that rely on multiple persistence units + locations (stored in various jars in the classpath for example), + Spring offers the + PersistenceUnitManager to act as a + central repository and avoid the (potentially expensive) persistence + units discovery process. The default implementation allows multiple + locations to be specified (by default, the classpath is searched for + 'META-INF/persistence.xml' files) which are + parsed and later on retrieved through the persistence unit + name: - <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> + <bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"> + <property name="persistenceXmlLocation"> + <list> + <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value> + <value>classpath:/my/package/**/custom-persistence.xml</value> + <value>classpath*:META-INF/persistence.xml</value> + </list> + </property> + <property name="dataSources"> + <map> + <entry key="localDataSource" value-ref="local-db"/> + <entry key="remoteDataSource" value-ref="remote-db"/> + </map> + </property> + <!-- if no datasource is specified, use this one --> + <property name="defaultDataSource" ref="remoteDataSource"/> +</bean> -</beans> +<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> + <property name="persistenceUnitManager" ref="pum"/> +</bean> - This assumes standard Java EE 5 bootstrapping, with the Java EE - server autodetecting persistence units (i.e. - META-INF/persistence.xml files in application jars) - and persistence-unit-ref entries in the Java EE - deployment descriptor (e.g. web.xml) defining - environment naming context locations for those persistence - units. + Note that the default implementation allows customization of the + persistence unit infos before feeding them to the JPA provider + declaratively through its properties (which affect + all hosted units) or programmatically, through + the PersistenceUnitPostProcessor (which + allows persistence unit selection). If no + PersistenceUnitManager is specified, + one will be created and used internally by + LocalContainerEntityManagerFactoryBean. +
+
- In such a scenario, the entire persistence unit deployment, - including the weaving (byte-code transformation) of persistent - classes, is up to the Java EE server. The JDBC - DataSource is defined through a JNDI - location in the META-INF/persistence.xml file; - EntityManager transactions are integrated with the server's JTA - subsystem. Spring merely uses the obtained - EntityManagerFactory, passing it on to - application objects via dependency injection, and managing - transactions for it (typically through - JtaTransactionManager). +
+ Implementing DAOs based on plain JPA - Note that, in case of multiple persistence units used in the - same application, the bean names of such a JNDI-retrieved persistence - units should match the persistence unit names that the application - uses to refer to them (e.g. in @PersistenceUnit and - @PersistenceContext annotations). + + While EntityManagerFactory + instances are thread-safe, + EntityManager instances are not. The + injected JPA EntityManager behave just + like an EntityManager fetched from an + application server's JNDI environment, as defined by the JPA + specification. It will delegate all calls to the current transactional + EntityManager, if any; else, it will + fall back to a newly created + EntityManager per operation, making it + thread-safe. + - Use this option when deploying to a Java EE 5 server. - Check your server's documentation on how to deploy a custom JPA - provider into your server, allowing for a different provider than the - server's default. -
+ It is possible to write code against the plain JPA without using + any Spring dependencies, using an injected + EntityManagerFactory or + EntityManager. Note that Spring can + understand @PersistenceUnit and + @PersistenceContext annotations both at + field and method level if a + PersistenceAnnotationBeanPostProcessor is + enabled. A corresponding DAO implementation might look like this: -
- <classname>LocalContainerEntityManagerFactoryBean</classname> + public class ProductDaoImpl implements ProductDao { - The - LocalContainerEntityManagerFactoryBean gives - full control over EntityManagerFactory - configuration and is appropriate for environments where fine-grained - customization is required. The - LocalContainerEntityManagerFactoryBean will - create a PersistenceUnitInfo based on - the persistence.xml file, the supplied - dataSourceLookup strategy and the specified - loadTimeWeaver. It is thus possible to work with - custom DataSources outside of JNDI and to control the weaving - process. + private EntityManagerFactory emf; - <beans> - - <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="dataSource" ref="someDataSource"/> - <property name="loadTimeWeaver"> - <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> - </property> - </bean> - -</beans> + @PersistenceUnit + public void setEntityManagerFactory(EntityManagerFactory emf) { + this.emf = emf; + } - A typical persistence.xml file looks as - follows: + public Collection loadProductsByCategory(String category) { + EntityManager em = this.emf.createEntityManager(); + try { + Query query = em.createQuery("from Product as p where p.category = ?1"); + query.setParameter(1, category); + return query.getResultList(); + } + finally { + if (em != null) { + em.close(); + } + } + } +} - <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> + The DAO above has no dependency on Spring and still fits nicely + into a Spring application context, just like it would if coded against + Spring's JpaTemplate. Moreover, the DAO takes + advantage of annotations to require the injection of the default + EntityManagerFactory: - <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL"> - <mapping-file>META-INF/orm.xml</mapping-file> - <exclude-unlisted-classes/> - </persistence-unit> + <beans> -</persistence> + <!-- bean post-processor for JPA annotations --> + <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> - NOTE: The "exclude-unlisted-classes" element always - indicates that NO scanning for annotated entity classes is supposed to - happen, in order to support the - <exclude-unlisted-classes/> shortcut. This is - in line with the JPA specification (which suggests that shortcut) but - unfortunately in conflict with the JPA XSD (which implies "false" for - that shortcut). As a consequence, - "<exclude-unlisted-classes> false - </exclude-unlisted-classes/>" is not supported! Simply - omit the "exclude-unlisted-classes" element if you would like entity - class scanning to actually happen. + <bean id="myProductDao" class="product.ProductDaoImpl"/> - This is the most powerful JPA setup option, allowing for - flexible local configuration within the application. It supports links - to an existing JDBC DataSource, - supports both local and global transactions, etc. However, it also - imposes requirements onto the runtime environment, such as the - availability of a weaving-capable ClassLoader if the persistence - provider demands byte-code transformation. +</beans> - Note that this option may conflict with the built-in JPA - capabilities of a Java EE 5 server. So when running in a full Java EE - 5 environment, consider obtaining your - EntityManagerFactory from JNDI. - Alternatively, specify a custom "persistenceXmlLocation" on your - LocalContainerEntityManagerFactoryBean - definition, e.g. "META-INF/my-persistence.xml", and only include a - descriptor with that name in your application jar files. Since the - Java EE 5 server will only look for default - META-INF/persistence.xml files, it will ignore such - custom persistence units and hence avoid conflicts with a - Spring-driven JPA setup upfront. (This applies to Resin 3.1, for - example.) + Note: As alternative to defining a + PersistenceAnnotationBeanPostProcessor + explicitly, consider using Spring 2.5's + context:annotation-config XML element in your + application context configuration. This will automatically register all + of Spring's standard post-processors for annotation-based configuration + (including CommonAnnotationBeanPostProcessor + etc). - Use this option for full JPA capabilities in a - Spring-based application environment. This includes web containers - such as Tomcat as well as standalone applications and integration - tests with sophisticated persistence requirements. + <beans> - - When is load-time weaving required? + <!-- post-processors for all standard config annotations --> + <context:annotation-config/> - Not all JPA providers impose the need of a JVM agent - (Hibernate being an example). If your provider does not require an - agent or you have other alternatives (for example applying - enhancements at build time through a custom compiler or an ant task) - the load-time weaver should not be - used. - + <bean id="myProductDao" class="product.ProductDaoImpl"/> - The LoadTimeWeaver interface is a - Spring-provided class that allows JPA - ClassTransformer instances to be - plugged in a specific manner depending on the environment (web - container/application server). Hooking - ClassTransformers through a Java 5 agent - is typically not efficient - the agents work against the - entire virtual machine and inspect - every class that is loaded - something that is - typically undesirable in a production server enviroment. +</beans> - Spring provides a number of - LoadTimeWeaver implementations for - various environments, allowing - ClassTransformer instances to be - applied only per ClassLoader and not per - VM. + The main issue with such a DAO is that it always creates a new + EntityManager via the factory. This can + be easily overcome by requesting a transactional + EntityManager (also called "shared + EntityManager", since it is a shared, thread-safe proxy for the actual + transactional EntityManager) to be injected instead of the + factory: - The following sections will discuss typical JPA weaving setup on - Tomcat as well as using Spring's VM agent. See the AOP chapter section - entitled for details on how to - set up general load-time weaving, covering Tomcat and the VM agent as - well as WebLogic, OC4J, GlassFish and Resin. + public class ProductDaoImpl implements ProductDao { -
- Tomcat load-time weaving setup (5.0+) + @PersistenceContext + private EntityManager em; - Apache Tomcat's - default ClassLoader does not support class transformation but allows - custom ClassLoaders to be used. Spring offers the - TomcatInstrumentableClassLoader (inside the - org.springframework.instrument.classloading.tomcat - package) which extends the Tomcat ClassLoader - (WebappClassLoader) and allows JPA - ClassTransformer instances to 'enhance' all - classes loaded by it. In short, JPA transformers will be applied - only inside a specific web application (which uses the - TomcatInstrumentableClassLoader). + public Collection loadProductsByCategory(String category) { + Query query = em.createQuery("from Product as p where p.category = :category"); + query.setParameter("category", category); + return query.getResultList(); + } +} - In order to use the custom ClassLoader on: + Note that the @PersistenceContext annotation + has an optional attribute type, which defaults to + PersistenceContextType.TRANSACTION. This default is + what you need to receive a "shared EntityManager" proxy. The + alternative, PersistenceContextType.EXTENDED, is a + completely different affair: This results in a so-called "extended + EntityManager", which is not thread-safe and hence + must not be used in a concurrently accessed component such as a + Spring-managed singleton bean. Extended EntityManagers are only supposed + to be used in stateful components that, for example, reside in a + session, with the lifecycle of the EntityManager not tied to a current + transaction but rather being completely up to the application. - - - Tomcat 5.0.x/5.5.x - + + Method and Field level Injection - - - Copy spring-tomcat-weaver.jar into - $CATALINA_HOME/server/lib (where - $CATALINA_HOME represents the root of the - Tomcat installation). - + Annotations that indicate dependency injections (such as + @PersistenceUnit and + @PersistenceContext) can be applied on field or + methods inside a class, therefore the expression "method/field level + injection". Field-level annotations concise and easier to use while + method-level allow for processing the injected dependency. In both + cases the member visibility (public, protected, private) does not + matter. - - Instruct Tomcat to use the custom ClassLoader (instead - of the default one) by editing the web application context - file: + What about class level annotations? - <Context path="/myWebApp" docBase="/my/webApp/location"> - <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> -</Context> + On the Java EE 5 platform, they are used for dependency + declaration and not for resource injection. + - Tomcat 5.0.x and 5.5.x series support several context - locations: server configuration file - ($CATALINA_HOME/conf/server.xml), the - default context configuration - ($CATALINA_HOME/conf/context.xml) that - affects all deployed web applications and per-webapp - configurations, deployed on the server - ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) - side or along with the webapp - (your-webapp.war/META-INF/context.xml). - For efficiency, inside the web-app configuration style is - recommended since only applications which use JPA will use the - custom ClassLoader. See the Tomcat 5.x documentation - for more details about available context locations. + The injected EntityManager is + Spring-managed (aware of the ongoing transaction). It is important to + note that even though the new implementation prefers method level + injection (of an EntityManager instead of + an EntityManagerFactory), no change is + required in the application context XML due to annotation usage. - Note that versions prior to 5.5.20 contained a bug in - the XML configuration parsing preventing usage of - Loader tag inside - server.xml (no matter if a ClassLoader is - specified or not (be it the official or a custom one). See - Tomcat's bugzilla for more - details. + The main advantage of this DAO style is that it depends on Java + Persistence API; no import of any Spring class is required. Moreover, as + the JPA annotations are understood, the injections are applied + automatically by the Spring container. This is of course appealing from + a non-invasiveness perspective, and might feel more natural to JPA + developers. +
- If you are using Tomcat 5.5.20+ you can set - useSystemClassLoaderAsParent to - false to fix the problem: <Context path="/myWebApp" docBase="/my/webApp/location"> - <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" - useSystemClassLoaderAsParent="false"/> -</Context> - - +
+ Exception Translation - - Tomcat 6.0.x - + However, the DAO throws the plain + PersistenceException exception class (which is + unchecked, and so does not have to be declared or caught) but also + IllegalArgumentException and + IllegalStateException, which means that callers + can only treat exceptions as generally fatal - unless they want to + depend on JPA'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 JPA-based and/or do not need any + special exception treatment. However, Spring offers a solution allowing + exception translation to be applied transparently through the + @Repository annotation: - - - Copy spring-tomcat-weaver.jar into - $CATALINA_HOME/lib (where - $CATALINA_HOME represents the root of the - Tomcat installation). - + @Repository +public class ProductDaoImpl implements ProductDao { - - Instruct Tomcat to use the custom ClassLoader (instead - of the default one) by editing the web application context - file: + // class body here... - <Context path="/myWebApp" docBase="/my/webApp/location"> - <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> -</Context> +} - Tomcat 6.0.x (similar to 5.0.x/5.5.x) series support - several context locations: server configuration file - ($CATALINA_HOME/conf/server.xml), the - default context configuration - ($CATALINA_HOME/conf/context.xml) that - affects all deployed web applications and per-webapp - configurations, deployed on the server - ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) - side or along with the webapp - (your-webapp.war/META-INF/context.xml). - For efficiency, inside the web-app configuration style is - recommended since only applications which use JPA will use the - custom ClassLoader. See the Tomcat 5.x documentation - for more details about available context locations. - - - + <beans> - The last step required on all Tomcat versions, is to use the - appropriate the LoadTimeWeaver when - configuring - LocalContainerEntityManagerFactoryBean: + <!-- Exception translation bean post processor --> + <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> - <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="loadTimeWeaver"> - <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/> - </property> -</bean> + <bean id="myProductDao" class="product.ProductDaoImpl"/> - Using this technique, JPA applications relying on - instrumentation, can run in Tomcat without the need of an agent. - This is important especially when hosting applications which rely on - different JPA implementations since the JPA transformers are applied - only at ClassLoader level and thus, are isolated from each - other. +</beans> - - If TopLink Essentials is being used a JPA provider under - Tomcat, please place the toplink-essentials jar under - $CATALINA_HOME/shared/lib folder instead of - your war. - -
+ The postprocessor will automatically look for all exception + translators (implementations of the + PersistenceExceptionTranslator interface) + and advise all beans marked with the + @Repository annotation so that the + discovered translators can intercept and apply the appropriate + translation on the thrown exceptions. + + In summary: DAOs can be implemented based on the plain Java + Persistence API and annotations, while still being able to benefit from + Spring-managed transactions, dependency injection, and transparent + exception conversion (if desired) to Spring's custom exception + hierarchies. +
+
+ +
+ <interfacename>JpaDialect</interfacename> -
- General load-time weaving using the VM agent + 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: - For environments where class instrumentation is required but - are not supported by the existing LoadTimeWeaver implementations, a - JDK agent can be the only solution. For such cases, Spring provides - InstrumentationLoadTimeWeaver which requires - a Spring-specific (but very general) VM agent (spring-agent.jar): + + + applying specific transaction semantics (such as custom + isolation level or transaction timeout) + - <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="loadTimeWeaver"> - <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> - </property> -</bean> + + retrieving the transactional JDBC + Connection (for exposure to JDBC-based + DAOs) + - Note that the virtual machine has to be started with the - Spring agent, by supplying the following JVM options: + + advanced translation of PersistenceExceptions + to Spring DataAccessExceptions + + - -javaagent:/path/to/spring-agent.jar -
+ 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. -
- Context-wide load-time weaver setup + See the JpaDialect Javadoc for more + details of its operations and how they are used within Spring's JPA + support. +
- Since Spring 2.5, a context-wide - LoadTimeWeaver can be configured - using the context:load-time-weaver configuration - element. Such a 'global' weaver will be picked up by all JPA - LocalContainerEntityManagerFactoryBeans - automatically. +
+ Transaction Management - This is the preferred way of setting up a load-time weaver, - delivering autodetection of the platform (WebLogic, OC4J, GlassFish, - Tomcat, Resin, VM agent) as well as automatic propagation of the - weaver to all weaver-aware beans. + To execute service operations within transactions, you can use + Spring's common declarative transaction facilities. For example: - <context:load-time-weaver/> + <?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="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - ... -</bean> + <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager"> + <property name="entityManagerFactory" ref="myEmf"/> + </bean> - See the section entitled - for details on how to set up general load-time weaving, covering - Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and - Resin. -
-
+ <bean id="myProductService" class="product.ProductServiceImpl"> + <property name="productDao" ref="myProductDao"/> + </bean> + + <aop:config> + <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/> + <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> + </aop:config> -
- Dealing with multiple persistence units + <tx:advice id="txAdvice" transaction-manager="myTxManager"> + <tx:attributes> + <tx:method name="increasePrice*" propagation="REQUIRED"/> + <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> + <tx:method name="*" propagation="SUPPORTS" read-only="true"/> + </tx:attributes> + </tx:advice> - For applications that rely on multiple persistence units - locations (stored in various jars in the classpath for example), - Spring offers the - PersistenceUnitManager to act as a - central repository and avoid the (potentially expensive) persistence - units discovery process. The default implementation allows multiple - locations to be specified (by default, the classpath is searched for - 'META-INF/persistence.xml' files) which are - parsed and later on retrieved through the persistence unit - name: +</beans> - <bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"> - <property name="persistenceXmlLocation"> - <list> - <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value> - <value>classpath:/my/package/**/custom-persistence.xml</value> - <value>classpath*:META-INF/persistence.xml</value> - </list> - </property> - <property name="dataSources"> - <map> - <entry key="localDataSource" value-ref="local-db"/> - <entry key="remoteDataSource" value-ref="remote-db"/> - </map> - </property> - <!-- if no datasource is specified, use this one --> - <property name="defaultDataSource" ref="remoteDataSource"/> -</bean> + Spring JPA allows a configured + JpaTransactionManager to expose a JPA transaction + to JDBC access code that accesses the same JDBC + DataSource, provided that the registered + JpaDialect supports retrieval of the + underlying JDBC Connection. Out of the box, + Spring provides dialects for the Toplink, Hibernate and OpenJPA JPA + implementations. See the next section for details on the + JpaDialect mechanism. +
-<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="persistenceUnitManager" ref="pum"/> -</bean> +
+ JDO - Note that the default implementation allows customization of the - persistence unit infos before feeding them to the JPA provider - declaratively through its properties (which affect - all hosted units) or programmatically, through - the PersistenceUnitPostProcessor (which - allows persistence unit selection). If no - PersistenceUnitManager is specified, - one will be created and used internally by - LocalContainerEntityManagerFactoryBean. -
-
+ 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. -
- <classname>JpaTemplate</classname> and - <classname>JpaDaoSupport</classname> +
+ <interfacename>PersistenceManagerFactory</interfacename> + setup - 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: + Spring provides a + LocalPersistenceManagerFactoryBean class that + allows for defining a local JDO + PersistenceManagerFactory within a Spring + application context: <beans> - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="entityManagerFactory" ref="myEmf"/> + <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"> + <property name="configLocation" value="classpath:kodo.properties"/> </bean> </beans> - public class JpaProductDao implements ProductDao { - - private JpaTemplate jpaTemplate; + 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 (): - public void setEntityManagerFactory(EntityManagerFactory emf) { - this.jpaTemplate = new JpaTemplate(emf); - } + <beans> - 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; - } - }); - } -} + <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> - 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); - } -} + <bean id="myPmf" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close"> + <property name="connectionFactory" ref="dataSource"/> + <property name="nontransactionalRead" value="true"/> + </bean> - 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.) -
+</beans> -
- Implementing DAOs based on plain JPA + 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. +
- - While EntityManagerFactory - instances are thread-safe, - EntityManager instances are not. The - injected JPA EntityManager behave just - like an EntityManager fetched from an - application server's JNDI environment, as defined by the JPA - specification. It will delegate all calls to the current transactional - EntityManager, if any; else, it will - fall back to a newly created - EntityManager per operation, making it - thread-safe. - +
+ Implementing DAOs based on the plain JDO API - It is possible to write code against the plain JPA without using - any Spring dependencies, using an injected - EntityManagerFactory or - EntityManager. Note that Spring can - understand @PersistenceUnit and - @PersistenceContext annotations both at - field and method level if a - PersistenceAnnotationBeanPostProcessor is - enabled. A corresponding DAO implementation might look like this: + 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 EntityManagerFactory emf; + private PersistenceManagerFactory persistenceManagerFactory; - @PersistenceUnit - public void setEntityManagerFactory(EntityManagerFactory emf) { - this.emf = emf; + public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { + this.persistenceManagerFactory = pmf; } public Collection loadProductsByCategory(String category) { - EntityManager em = this.emf.createEntityManager(); + PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager(); try { - Query query = em.createQuery("from Product as p where p.category = ?1"); - query.setParameter(1, category); - return query.getResultList(); + Query query = pm.newQuery(Product.class, "category = pCategory"); + query.declareParameters("String pCategory"); + return query.execute(category); } finally { - if (em != null) { - em.close(); - } + pm.close(); } } } - The DAO above has no dependency on Spring and still fits nicely - into a Spring application context, just like it would if coded against - Spring's JpaTemplate. Moreover, the DAO takes - advantage of annotations to require the injection of the default - EntityManagerFactory: + 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 post-processor for JPA annotations --> - <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> - - <bean id="myProductDao" class="product.ProductDaoImpl"/> + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="persistenceManagerFactory" ref="myPmf"/> + </bean> </beans> - Note: As alternative to defining a - PersistenceAnnotationBeanPostProcessor - explicitly, consider using Spring 2.5's - context:annotation-config XML element in your - application context configuration. This will automatically register all - of Spring's standard post-processors for annotation-based configuration - (including CommonAnnotationBeanPostProcessor - etc). + 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> - <!-- post-processors for all standard config annotations --> - <context:annotation-config/> + <bean id="myPmfProxy" + class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"> + <property name="targetPersistenceManagerFactory" ref="myPmf"/> + </bean> - <bean id="myProductDao" class="product.ProductDaoImpl"/> + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="persistenceManagerFactory" ref="myPmfProxy"/> + </bean> </beans> - The main issue with such a DAO is that it always creates a new - EntityManager via the factory. This can - be easily overcome by requesting a transactional - EntityManager (also called "shared - EntityManager", since it is a shared, thread-safe proxy for the actual - transactional EntityManager) to be injected instead of the - factory: + 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 { - @PersistenceContext - private EntityManager em; + private PersistenceManagerFactory persistenceManagerFactory; + + public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { + this.persistenceManagerFactory = pmf; + } public Collection loadProductsByCategory(String category) { - Query query = em.createQuery("from Product as p where p.category = :category"); - query.setParameter("category", category); - return query.getResultList(); + PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager(); + Query query = pm.newQuery(Product.class, "category = pCategory"); + query.declareParameters("String pCategory"); + return query.execute(category); } } - Note that the @PersistenceContext annotation - has an optional attribute type, which defaults to - PersistenceContextType.TRANSACTION. This default is - what you need to receive a "shared EntityManager" proxy. The - alternative, PersistenceContextType.EXTENDED, is a - completely different affair: This results in a so-called "extended - EntityManager", which is not thread-safe and hence - must not be used in a concurrently accessed component such as a - Spring-managed singleton bean. Extended EntityManagers are only supposed - to be used in stateful components that, for example, reside in a - session, with the lifecycle of the EntityManager not tied to a current - transaction but rather being completely up to the application. + With such DAOs that rely on active transactions, it is recommended + to enforce active transactions through turning + TransactionAwarePersistenceManagerFactoryProxy's + "allowCreate" flag off: - - Method and Field level Injection + <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 + + - Annotations that indicate dependency injections (such as - @PersistenceUnit and - @PersistenceContext) can be applied on field or - methods inside a class, therefore the expression "method/field level - injection". Field-level annotations concise and easier to use while - method-level allow for processing the injected dependency. In both - cases the member visibility (public, protected, private) does not - matter. + See the JdoDialect Javadoc for more details + on its operations and how they are used within Spring's JDO + support. +
+
- What about class level annotations? +
+ iBATIS SQL Maps - On the Java EE 5 platform, they are used for dependency - declaration and not for resource injection. - + 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. - The injected EntityManager is - Spring-managed (aware of the ongoing transaction). It is important to - note that even though the new implementation prefers method level - injection (of an EntityManager instead of - an EntityManagerFactory), no change is - required in the application context XML due to annotation usage. + 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. - The main advantage of this DAO style is that it depends on Java - Persistence API; no import of any Spring class is required. Moreover, as - the JPA annotations are understood, the injections are applied - automatically by the Spring container. This is of course appealing from - a non-invasiveness perspective, and might feel more natural to JPA - developers. -
+ + 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. + -
- Exception Translation +
+ Setting up the <classname>SqlMapClient</classname> - However, the DAO throws the plain - PersistenceException exception class (which is - unchecked, and so does not have to be declared or caught) but also - IllegalArgumentException and - IllegalStateException, which means that callers - can only treat exceptions as generally fatal - unless they want to - depend on JPA'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 JPA-based and/or do not need any - special exception treatment. However, Spring offers a solution allowing - exception translation to be applied transparently through the - @Repository annotation: + If we want to map the previous Account class with iBATIS 2.x we + need to create the following SQL map + 'Account.xml': - @Repository -public class ProductDaoImpl implements ProductDao { + <sqlMap namespace="Account"> - // class body here... + <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> - <beans> + <insert id="insertAccount"> + insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#) + </insert> - <!-- Exception translation bean post processor --> - <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> +</sqlMap> - <bean id="myProductDao" class="product.ProductDaoImpl"/> + The configuration file for iBATIS 2 looks like this: -</beans> + <sqlMapConfig> - The postprocessor will automatically look for all exception - translators (implementations of the - PersistenceExceptionTranslator interface) - and advise all beans marked with the - @Repository annotation so that the - discovered translators can intercept and apply the appropriate - translation on the thrown exceptions. + <sqlMap resource="example/Account.xml"/> - In summary: DAOs can be implemented based on the plain Java - Persistence API and annotations, while still being able to benefit from - Spring-managed transactions, dependency injection, and transparent - exception conversion (if desired) to Spring's custom exception - hierarchies. -
-
+</sqlMapConfig>
-
- Transaction Management + Remember that iBATIS loads resources from the class path, so be + sure to add the 'Account.xml' file to the class + path. - To execute service operations within transactions, you can use - Spring's common declarative transaction facilities. For example: + 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. - <?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"> + <beans> - <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager"> - <property name="entityManagerFactory" ref="myEmf"/> + <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="myProductService" class="product.ProductServiceImpl"> - <property name="productDao" ref="myProductDao"/> + <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> + <property name="configLocation" value="WEB-INF/sqlmap-config.xml"/> + <property name="dataSource" ref="dataSource"/> </bean> - - <aop:config> - <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/> - <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> - </aop:config> - - <tx:advice id="txAdvice" transaction-manager="myTxManager"> - <tx:attributes> - <tx:method name="increasePrice*" propagation="REQUIRED"/> - <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> - <tx:method name="*" propagation="SUPPORTS" read-only="true"/> - </tx:attributes> - </tx:advice> </beans> +
- Spring JPA allows a configured - JpaTransactionManager to expose a JPA transaction - to JDBC access code that accesses the same JDBC - DataSource, provided that the registered - JpaDialect supports retrieval of the - underlying JDBC Connection. Out of the box, - Spring provides dialects for the Toplink, Hibernate and OpenJPA JPA - implementations. See the next section for details on the - JpaDialect mechanism. -
+
+ Implementing DAOs based on plain iBATIS API -
- <interfacename>JpaDialect</interfacename> + 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: - 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: + public class SqlMapAccountDao implements AccountDao { + + private SqlMapClient sqlMapClient; + + public void setSqlMapClient(SqlMapClient sqlMapClient) { + this.sqlMapClient = sqlMapClient; + } - - - applying specific transaction semantics (such as custom - isolation level or transaction timeout) - + public Account getAccount(String email) { + try { + return (Account) this.sqlMapClient.queryForObject("getAccountByEmail", email); + } + catch (SQLException ex) { + throw new MyDaoException(ex); + } + } - - retrieving the transactional JDBC - Connection (for exposure to JDBC-based - DAOs) - + public void insertAccount(Account account) throws DataAccessException { + try { + this.sqlMapClient.update("insertAccount", account); + } + catch (SQLException ex) { + throw new MyDaoException(ex); + } + } +} - - advanced translation of PersistenceExceptions - to Spring DataAccessExceptions - - + 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: - 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. + <beans> - See the JpaDialect Javadoc for more - details of its operations and how they are used within Spring's JPA - support. + <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 @@ +