diff --git a/spring-framework-reference/src/classic-spring.xml b/spring-framework-reference/src/classic-spring.xml index 27f41258bdd..53a879f0e18 100644 --- a/spring-framework-reference/src/classic-spring.xml +++ b/spring-framework-reference/src/classic-spring.xml @@ -15,8 +15,7 @@ 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. - + usage patterns, please refer to the chapter.
Hibernate @@ -170,96 +169,6 @@
-
- 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 @@ -347,77 +256,93 @@
-
- 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 { +
+ JPA - public Account getAccount(String email) throws DataAccessException { - return (Account) getSqlMapClientTemplate().queryForObject("getAccountByEmail", email); - } + For the currently recommended usage patterns for JPA see - public void insertAccount(Account account) throws DataAccessException { - getSqlMapClientTemplate().update("insertAccount", account); - } -} +
+ <classname>JpaTemplate</classname> and + <classname>JpaDaoSupport</classname> - 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: + 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="accountDao" class="example.SqlMapAccountDao"> - <property name="sqlMapClient" ref="sqlMapClient"/> + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="entityManagerFactory" ref="myEmf"/> </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(); + 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; } }); } } - 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. + 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.
diff --git a/spring-framework-reference/src/orm.xml b/spring-framework-reference/src/orm.xml index 4a55059f74c..51441edcf60 100644 --- a/spring-framework-reference/src/orm.xml +++ b/spring-framework-reference/src/orm.xml @@ -8,17 +8,18 @@ Introduction The Spring Framework provides integration with Hibernate, - JDO, iBATIS SQL Maps and JPA: in terms of + JPA, JDO and iBATIS SQL Maps: in terms of resource management, DAO implementation support, and transaction strategies. For example for Hibernate, there is first-class support with lots of IoC convenience features, addressing many typical Hibernate integration issues. All of these support packages for O/R (Object - Relational) mappers comply with Spring's generic transaction and DAO - exception hierarchies. There are usually two integration styles: either - using Spring's DAO 'templates' or coding DAOs against plain - Hibernate/JDO/JPA/etc APIs. In both cases, DAOs can be configured through - Dependency Injection and participate in Spring's resource and transaction - management. + Relational) mappers can be configured through Dependency Injection, can + participate in Spring's resource and transaction management and they + comply with Spring's generic transaction and DAO exception hierarchies. + The curently recommended integration style is to code DAOs against plain + Hibernate/JPA/JDO/etc APIs. The older style of using Spring's DAO + 'templates' is no longer recommended and the coverage of this style can be + found in the Appendix. Spring adds significant support when using the O/R mapping layer of your choice to create data access applications. First of all, you should @@ -106,15 +107,119 @@ It also leverages declarative transaction demarcation with different transaction strategies. - The JPetStore sample illustrates the use of iBATIS SQL Maps in a - Spring environment. It also features two web tier versions: one based on - Spring Web MVC, one based on Struts. - Beyond the samples shipped with Spring, there are a variety of - Spring-based O/R mapping samples provided by specific vendors: for - example, the JDO implementations JPOX () and Kodo (). + Spring-based O/R mapping samples provided by specific vendors. +
+ +
+ General ORM integration considerations + + This section highlights some common considerations regardles of + which ORM technology you use. The Hibernate section provides more details + and also show these features/configurations in a concrete context. + + The major goal is to allow for clear application layering, with any + data access and transaction technology, and for loose coupling of + application objects. No more business service dependencies on the data + access or transaction strategy, no more hard-coded resource lookups, no + more hard-to-replace singletons, no more custom service registries. One + simple and consistent approach to wiring up application objects, keeping + them as reusable and free from container dependencies as possible. All the + individual data access features are usable on their own but integrate + nicely with Spring's application context concept, providing XML-based + configuration and cross-referencing of plain JavaBean instances that don't + need to be Spring-aware. In a typical Spring application, many important + objects are JavaBeans: data access templates, data access objects, + transaction managers, business services (that use the data access objects + and transaction managers), web view resolvers, web controllers (that use + the business services),and so on. + +
+ Resource and Transaction management + + Typical business applications are often cluttered with repetitive + resource management code. Many projects try to invent their own + solutions for this issue, sometimes sacrificing proper handling of + failures for programming convenience. Spring advocates strikingly simple + solutions for proper resource handling, namely IoC via templating in the + case of JDBC and applying AOP interceptors for the ORM technologies. + + + The infrastructure cares for proper resource handling, and for + appropriate conversion of specific API exceptions to an unchecked + infrastructure exception hierarchy. Spring introduces a DAO exception + hierarchy, applicable to any data access strategy. For direct JDBC, the + JdbcTemplate class mentioned in a previous + section cares for connection handling, and for proper conversion of + SQLException to the + DataAccessException hierarchy, including + translation of database-specific SQL error codes to meaningful exception + classes. For ORM technologies, see the next section for how to get the + same exception translation benefits. + + When it comes to transaction management the + JdbcTemplate class hooks in to the Spring + transaction support and supports both JTA and JDBC transactions, via + respective Spring transaction managers. For the supported ORM + technologies Spring offers Hibernate, JPA and JDO support via the + Hibernate / JPA / JDO transaction managers as well as JTA support. For + more details on the transaction support see the chapter. +
+ +
+ Exception Translation + + Using Hibernate, JDO or JPA in a DAO means that you will have to + decide how to handle the persistence technology's native exception + classes. The DAO could potentially throw a subclass of a + HibernateException, + JDOException or + PersistenceException depending on the technology + in use. These exceptions are all run-time exceptions and does not have + to be declared or caught. You would potentially also have to deal with + IllegalArgumentException and + IllegalStateException. This means that callers + can only treat exceptions as generally fatal - unless they want to + depend on the persistence technology's own exception structure. Catching + specific causes such as an optimistic locking failure is not possible + without tying the caller to the implementation strategy. This tradeoff + might be acceptable to applications that are strongly ORM-based and/or + do not need any special exception treatment. However, Spring offers a + solution allowing exception translation to be applied transparently + through the @Repository + annotation: + + @Repository +public class ProductDaoImpl implements ProductDao { + + // class body here... + +} + + <beans> + + <!-- Exception translation bean post processor --> + <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> + + <bean id="myProductDao" class="product.ProductDaoImpl"/> + +</beans> + + 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 persistence + technology's API and annotations, while still being able to benefit from + Spring-managed transactions, dependency injection, and transparent + exception conversion (if desired) to Spring's custom exception + hierarchies. +
@@ -134,51 +239,6 @@ higher. Neither Hibernate 2.1 nor Hibernate 3.0 are supported anymore. -
- Resource management - - Typical business applications are often cluttered with repetitive - resource management code. Many projects try to invent their own - solutions for this issue, sometimes sacrificing proper handling of - failures for programming convenience. Spring advocates strikingly simple - solutions for proper resource handling, namely IoC via templating; for - example infrastructure classes with callback interfaces, or applying AOP - interceptors. The infrastructure cares for proper resource handling, and - for appropriate conversion of specific API exceptions to an unchecked - infrastructure exception hierarchy. Spring introduces a DAO exception - hierarchy, applicable to any data access strategy. For direct JDBC, the - JdbcTemplate class mentioned in a previous - section cares for connection handling, and for proper conversion of - SQLException to the - DataAccessException hierarchy, including - translation of database-specific SQL error codes to meaningful exception - classes. It supports both JTA and JDBC transactions, via respective - Spring transaction managers. - - Spring also offers Hibernate and JDO support, consisting of a - HibernateTemplate / - JdoTemplate analogous to - JdbcTemplate, a - HibernateInterceptor / - JdoInterceptor, and a Hibernate / JDO transaction - manager. The major goal is to allow for clear application layering, with - any data access and transaction technology, and for loose coupling of - application objects. No more business service dependencies on the data - access or transaction strategy, no more hard-coded resource lookups, no - more hard-to-replace singletons, no more custom service registries. One - simple and consistent approach to wiring up application objects, keeping - them as reusable and free from container dependencies as possible. All - the individual data access features are usable on their own but - integrate nicely with Spring's application context concept, providing - XML-based configuration and cross-referencing of plain JavaBean - instances that don't need to be Spring-aware. In a typical Spring - application, many important objects are JavaBeans: data access - templates, data access objects (that use the templates), transaction - managers, business services (that use the data access objects and - transaction managers), web view resolvers, web controllers (that use the - business services),and so on. -
-
<interfacename>SessionFactory</interfacename> setup in a Spring container @@ -801,991 +861,1004 @@ cache. - -
-
- JPA - - 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. - -
- JPA setup in a Spring environment +
+ JDO - Spring JPA offers three ways of setting up JPA - EntityManagerFactory: + 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>LocalEntityManagerFactoryBean</classname> +
+ <interfacename>PersistenceManagerFactory</interfacename> + setup - 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: + Spring provides a + LocalPersistenceManagerFactoryBean class that + allows for defining a local JDO + PersistenceManagerFactory within a Spring + application context: - <beans> + <beans> - <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> - <property name="persistenceUnitName" value="myPersistenceUnit"/> - </bean> + <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"> + <property name="configLocation" value="classpath:kodo.properties"/> + </bean> </beans> - 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). + 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 DataNucleus (formerly JPOX) (http://www.datanucleus.org/): - Only use this option in simple deployment environments - like standalone applications and integration tests. -
+ <beans> -
- <classname>Obtaining an EntityManagerFactory from - JNDI</classname> + <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> - Obtaining an EntityManagerFactory - from JNDI (for example in a Java EE 5 environment), is just a matter - of changing the XML configuration: + <bean id="myPmf" class="org.datanucleus.jdo.JDOPersistenceManagerFactory" destroy-method="close"> + <property name="connectionFactory" ref="dataSource"/> + <property name="nontransactionalRead" value="true"/> + </bean> - <beans> +</beans> - <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> + 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. +
-</beans>
+
+ Implementing DAOs based on the plain JDO API - 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. + 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: - 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). + public class ProductDaoImpl implements ProductDao { - 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). + private PersistenceManagerFactory persistenceManagerFactory; - 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 void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { + this.persistenceManagerFactory = pmf; + } -
- <classname>LocalContainerEntityManagerFactoryBean</classname> + 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(); + } + } +} - 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. + As the above DAO still follows the Dependency Injection pattern, + it still fits nicely into a Spring container, just like it would if + coded against Spring's JdoTemplate: - <beans> - - <bean id="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> + <beans> - A typical persistence.xml file looks as - follows: + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="persistenceManagerFactory" ref="myPmf"/> + </bean> - <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> - -</persistence> - - 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. - - 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. - - 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.) - - 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. - - - When is load-time weaving required? + 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. - 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. - + <beans> - 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. + <bean id="myPmfProxy" + class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"> + <property name="targetPersistenceManagerFactory" ref="myPmf"/> + </bean> - Spring provides a number of - LoadTimeWeaver implementations for - various environments, allowing - ClassTransformer instances to be - applied only per ClassLoader and not per - VM. + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="persistenceManagerFactory" ref="myPmfProxy"/> + </bean> - 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. +</beans> -
- Tomcat load-time weaving setup (5.0+) + 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. - 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). + 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: - In order to use the custom ClassLoader on: + public class ProductDaoImpl implements ProductDao { - - - Tomcat 5.0.x/5.5.x - + private PersistenceManagerFactory persistenceManagerFactory; - - - Copy spring-tomcat-weaver.jar into - $CATALINA_HOME/server/lib (where - $CATALINA_HOME represents the root of the - Tomcat installation). - + public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { + this.persistenceManagerFactory = pmf; + } - - Instruct Tomcat to use the custom ClassLoader (instead - of the default one) by editing the web application context - file: + 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); + } +} - <Context path="/myWebApp" docBase="/my/webApp/location"> - <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> -</Context> + With such DAOs that rely on active transactions, it is recommended + to enforce active transactions through turning + TransactionAwarePersistenceManagerFactoryProxy's + "allowCreate" flag off: - 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. + <beans> - 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. + <bean id="myPmfProxy" + class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"> + <property name="targetPersistenceManagerFactory" ref="myPmf"/> + <property name="allowCreate" value="false"/> + </bean> - 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> - - + <bean id="myProductDao" class="product.ProductDaoImpl"> + <property name="persistenceManagerFactory" ref="myPmfProxy"/> + </bean> - - Tomcat 6.0.x - +</beans> - - - Copy spring-tomcat-weaver.jar into - $CATALINA_HOME/lib (where - $CATALINA_HOME represents the root of the - Tomcat installation). - + 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. - - Instruct Tomcat to use the custom ClassLoader (instead - of the default one) by editing the web application context - file: + 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. - <Context path="/myWebApp" docBase="/my/webApp/location"> - <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> -</Context> + 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). +
- 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. - - - +
+ Transaction management - The last step required on all Tomcat versions, is to use the - appropriate the LoadTimeWeaver when - configuring - LocalContainerEntityManagerFactoryBean: + To execute service operations within transactions, you can use + Spring's common declarative transaction facilities. For example: - <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="loadTimeWeaver"> - <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/> - </property> -</bean> + <?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"> - 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. + <bean id="myTxManager" class="org.springframework.orm.jdo.JdoTransactionManager"> + <property name="persistenceManagerFactory" ref="myPmf"/> + </bean> - - 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. - -
+ <bean id="myProductService" class="product.ProductServiceImpl"> + <property name="productDao" ref="myProductDao"/> + </bean> -
- General load-time weaving using the VM agent + <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> - 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): + <aop:config> + <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/> + <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> + </aop:config> - <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="loadTimeWeaver"> - <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> - </property> -</bean> +</beans> - Note that the virtual machine has to be started with the - Spring agent, by supplying the following JVM options: + 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). - -javaagent:/path/to/spring-agent.jar -
+ 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. +
-
- Context-wide load-time weaver setup +
+ <interfacename>JdoDialect</interfacename> - 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. + 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: - 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. + + + applying specific transaction semantics (such as custom + isolation level or transaction timeout) + - <context:load-time-weaver/> + + retrieving the transactional JDBC + Connection (for exposure to + JDBC-based DAOs) + -<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - ... -</bean> + + applying query timeouts (automatically calculated from + Spring-managed transaction timeout) + - 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. -
-
+ + eagerly flushing a + PersistenceManager (to make + transactional changes visible to JDBC-based data access code) + -
- Dealing with multiple persistence units + + advanced translation of JDOExceptions to + Spring DataAccessExceptions + + - 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: + See the JdoDialect Javadoc for more details + on its operations and how they are used within Spring's JDO + support. +
+
- <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> +
+ JPA -<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> - <property name="persistenceUnitManager" ref="pum"/> -</bean> + 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. - 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. -
-
+
+ JPA setup in a Spring environment -
- Implementing DAOs based on plain JPA + Spring JPA offers three ways of setting up JPA + EntityManagerFactory: - - 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. - +
+ <classname>LocalEntityManagerFactoryBean</classname> - 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: + 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: - public class ProductDaoImpl implements ProductDao { + <beans> - private EntityManagerFactory emf; + <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> + <property name="persistenceUnitName" value="myPersistenceUnit"/> + </bean> - @PersistenceUnit - public void setEntityManagerFactory(EntityManagerFactory emf) { - this.emf = emf; - } +</beans> - 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(); - } - } - } -} + 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). - 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: + Only use this option in simple deployment environments + like standalone applications and integration tests. +
- <beans> +
+ <classname>Obtaining an EntityManagerFactory from + JNDI</classname> - <!-- bean post-processor for JPA annotations --> - <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> + Obtaining an EntityManagerFactory + from JNDI (for example in a Java EE 5 environment), is just a matter + of changing the XML configuration: - <bean id="myProductDao" class="product.ProductDaoImpl"/> + <beans> + + <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> </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). + 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. - <beans> + 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). - <!-- post-processors for all standard config annotations --> - <context:annotation-config/> + 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). - <bean id="myProductDao" class="product.ProductDaoImpl"/> + 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. +
-</beans>
+
+ <classname>LocalContainerEntityManagerFactoryBean</classname> - 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 + 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 class ProductDaoImpl implements ProductDao { + <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> - @PersistenceContext - private EntityManager em; + A typical persistence.xml file looks as + follows: - public Collection loadProductsByCategory(String category) { - Query query = em.createQuery("from Product as p where p.category = :category"); - query.setParameter("category", category); - return query.getResultList(); - } -} + <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> - 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. + <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL"> + <mapping-file>META-INF/orm.xml</mapping-file> + <exclude-unlisted-classes/> + </persistence-unit> - - Method and Field level Injection +</persistence> - 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. + 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. - What about class level annotations? + 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. - On the Java EE 5 platform, they are used for dependency - declaration and not for resource injection. - + 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.) - 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. + 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. - 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. -
+ + When is load-time weaving required? -
- Exception Translation + 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. + - 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: + 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. - @Repository -public class ProductDaoImpl implements ProductDao { + Spring provides a number of + LoadTimeWeaver implementations for + various environments, allowing + ClassTransformer instances to be + applied only per ClassLoader and not per + VM. - // class body here... + 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. -} +
+ Tomcat load-time weaving setup (5.0+) - <beans> + 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). - <!-- Exception translation bean post processor --> - <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> + In order to use the custom ClassLoader on: - <bean id="myProductDao" class="product.ProductDaoImpl"/> + + + 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). + - 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. + + Instruct Tomcat to use the custom ClassLoader (instead + of the default one) by editing the web application context + file: - 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. -
-
+ <Context path="/myWebApp" docBase="/my/webApp/location"> + <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> +</Context> -
- <interfacename>JpaDialect</interfacename> + 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. - 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: + 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. - - - applying specific transaction semantics (such as custom - isolation level or transaction timeout) - + 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> + + - - retrieving the transactional JDBC - Connection (for exposure to JDBC-based - DAOs) - + + Tomcat 6.0.x + - - advanced translation of PersistenceExceptions - to Spring DataAccessExceptions - - + + + Copy spring-tomcat-weaver.jar into + $CATALINA_HOME/lib (where + $CATALINA_HOME represents the root of the + Tomcat installation). + - 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. + + Instruct Tomcat to use the custom ClassLoader (instead + of the default one) by editing the web application context + file: - See the JpaDialect Javadoc for more - details of its operations and how they are used within Spring's JPA - support. -
+ <Context path="/myWebApp" docBase="/my/webApp/location"> + <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> +</Context> -
- Transaction Management + 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. + + + - To execute service operations within transactions, you can use - Spring's common declarative transaction facilities. For example: + The last step required on all Tomcat versions, is to use the + appropriate the LoadTimeWeaver when + configuring + LocalContainerEntityManagerFactoryBean: - <?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"> + <property name="loadTimeWeaver"> + <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/> + </property> +</bean> - <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager"> - <property name="entityManagerFactory" ref="myEmf"/> - </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. - <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> + + 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. + +
- <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> +
+ General load-time weaving using the VM agent -</beans> + 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): - 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="loadTimeWeaver"> + <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> + </property> +</bean> -
- JDO + Note that the virtual machine has to be started with the + Spring agent, by supplying the following JVM options: - 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. + -javaagent:/path/to/spring-agent.jar +
-
- <interfacename>PersistenceManagerFactory</interfacename> - setup +
+ Context-wide load-time weaver setup - Spring provides a - LocalPersistenceManagerFactoryBean class that - allows for defining a local JDO - PersistenceManagerFactory within a Spring - application context: + 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. - <beans> + 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. - <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"> - <property name="configLocation" value="classpath:kodo.properties"/> - </bean> + <context:load-time-weaver/> -</beans> +<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> + ... +</bean> - 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 (): + 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. +
+
- <beans> +
+ Dealing with multiple persistence units - <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> + 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: - <bean id="myPmf" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close"> - <property name="connectionFactory" ref="dataSource"/> - <property name="nontransactionalRead" value="true"/> - </bean> + <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> - 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. + 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. +
-
- Implementing DAOs based on the plain JDO API +
+ Implementing DAOs based on plain JPA - 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: + + 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. + + + 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: public class ProductDaoImpl implements ProductDao { - private PersistenceManagerFactory persistenceManagerFactory; + private EntityManagerFactory emf; - public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { - this.persistenceManagerFactory = pmf; + @PersistenceUnit + public void setEntityManagerFactory(EntityManagerFactory emf) { + this.emf = emf; } public Collection loadProductsByCategory(String category) { - PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager(); + EntityManager em = this.emf.createEntityManager(); try { - Query query = pm.newQuery(Product.class, "category = pCategory"); - query.declareParameters("String pCategory"); - return query.execute(category); + Query query = em.createQuery("from Product as p where p.category = ?1"); + query.setParameter(1, category); + return query.getResultList(); } finally { - pm.close(); + if (em != null) { + em.close(); + } } } } - As the above DAO still follows the Dependency Injection pattern, - it still fits nicely into a Spring container, just like it would if - coded against Spring's JdoTemplate: + The DAO above has no dependency on Spring and still fits nicely + into a Spring application context. Moreover, the DAO takes advantage of + annotations to require the injection of the default + EntityManagerFactory: <beans> - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="persistenceManagerFactory" ref="myPmf"/> - </bean> + <!-- bean post-processor for JPA annotations --> + <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> + + <bean id="myProductDao" class="product.ProductDaoImpl"/> </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. + 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). <beans> - <bean id="myPmfProxy" - class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"> - <property name="targetPersistenceManagerFactory" ref="myPmf"/> - </bean> + <!-- post-processors for all standard config annotations --> + <context:annotation-config/> - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="persistenceManagerFactory" ref="myPmfProxy"/> - </bean> + <bean id="myProductDao" class="product.ProductDaoImpl"/> </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: + 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: public class ProductDaoImpl implements ProductDao { - private PersistenceManagerFactory persistenceManagerFactory; + @PersistenceContext + private EntityManager em; + + public Collection loadProductsByCategory(String category) { + Query query = em.createQuery("from Product as p where p.category = :category"); + query.setParameter("category", category); + return query.getResultList(); + } +} + + 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. + + + Method and Field level Injection + + 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. + + What about class level annotations? - public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { - this.persistenceManagerFactory = pmf; - } + On the Java EE 5 platform, they are used for dependency + declaration and not for resource injection. + - 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); - } -} + 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. - With such DAOs that rely on active transactions, it is recommended - to enforce active transactions through turning - TransactionAwarePersistenceManagerFactoryProxy's - "allowCreate" flag off: + 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. +
+
- <beans> +
+ <interfacename>JpaDialect</interfacename> - <bean id="myPmfProxy" - class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy"> - <property name="targetPersistenceManagerFactory" ref="myPmf"/> - <property name="allowCreate" value="false"/> - </bean> + 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: - <bean id="myProductDao" class="product.ProductDaoImpl"> - <property name="persistenceManagerFactory" ref="myPmfProxy"/> - </bean> + + + applying specific transaction semantics (such as custom + isolation level or transaction timeout) + -</beans> + + retrieving the transactional JDBC + Connection (for exposure to JDBC-based + DAOs) + - 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. + + advanced translation of PersistenceExceptions + to Spring DataAccessExceptions + + - 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. + 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. - 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). -
+ See the JpaDialect Javadoc for more + details of its operations and how they are used within Spring's JPA + support. +
-
- Transaction management +
+ Transaction Management - To execute service operations within transactions, you can use - Spring's common declarative transaction facilities. For example: + 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"> + <?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 id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager"> + <property name="entityManagerFactory" ref="myEmf"/> </bean> <bean id="myProductService" class="product.ProductServiceImpl"> <property name="productDao" ref="myProductDao"/> </bean> + + <aop:config> + <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/> + <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/> + </aop:config> - <tx:advice id="txAdvice" transaction-manager="txManager"> + <tx:advice id="txAdvice" transaction-manager="myTxManager"> <tx:attributes> <tx:method name="increasePrice*" propagation="REQUIRED"/> <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/> @@ -1793,90 +1866,27 @@ public class ProductDaoImpl implements ProductDao { </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. -
+ 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.
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. + The iBATIS support in the Spring Framework much resembles the JDBC + support in that it supports the same template style programming and just + as with JDBC or other ORM technologies, the iBATIS support works with + Spring's exception hierarchy and let's you enjoy the all IoC features + Spring has. Transaction management can be handled through Spring's standard facilities. There are no special transaction strategies for iBATIS, as @@ -1887,11 +1897,9 @@ public class ProductDaoImpl implements ProductDao { 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. + Spring supports iBatis 2.x. The iBatis 1.x support classes were + moved to the Spring Modules project as of Spring 2.0, and you are + directed there for documentation.
@@ -1955,6 +1963,71 @@ public class ProductDaoImpl implements ProductDao { </beans>
+
+ Using <classname>SqlMapClientTemplate</classname> and + <classname>SqlMapClientDaoSupport</classname> + + The SqlMapClientDaoSupport class offers a + supporting class similar to the SqlMapDaoSupport. + We extend it to implement our DAO: + + public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao { + + public Account getAccount(String email) throws DataAccessException { + return (Account) getSqlMapClientTemplate().queryForObject("getAccountByEmail", email); + } + + public void insertAccount(Account account) throws DataAccessException { + getSqlMapClientTemplate().update("insertAccount", account); + } +} + + In the DAO, we use the pre-configured + SqlMapClientTemplate to execute the queries, + after setting up the SqlMapAccountDao in the + application context and wiring it with our + SqlMapClient instance: + + <beans> + + <bean id="accountDao" class="example.SqlMapAccountDao"> + <property name="sqlMapClient" ref="sqlMapClient"/> + </bean> + +</beans> + + Note that a SqlMapTemplate instance could + also be created manually, passing in the SqlMapClient + as constructor argument. The SqlMapClientDaoSupport + base class simply pre-initializes a + SqlMapClientTemplate instance for us. + + The SqlMapClientTemplate also offers a + generic execute method, taking a custom + SqlMapClientCallback implementation as argument. This + can, for example, be used for batching: + + public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao { + + public void insertAccount(Account account) throws DataAccessException { + getSqlMapClientTemplate().execute(new SqlMapClientCallback() { + public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException { + executor.startBatch(); + executor.update("insertAccount", account); + executor.update("insertAddress", account.getAddress()); + executor.executeBatch(); + } + }); + } +} + + In general, any combination of operations offered by the native + SqlMapExecutor API can be used in such a callback. + Any SQLException thrown will automatically get + converted to Spring's generic DataAccessException + hierarchy. +
+
Implementing DAOs based on plain iBATIS API