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
-
-
- JpaTemplate and
- JpaDaoSupport
-
- 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 SqlMapClientTemplate and
- SqlMapClientDaoSupport
-
- 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);
- }
-}
+
+ JpaTemplate and
+ JpaDaoSupport
- 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.
-
-
SessionFactory 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.
-
- LocalEntityManagerFactoryBean
+
+ PersistenceManagerFactory
+ 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>
-
- Obtaining an EntityManagerFactory from
- JNDI
+ <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;
+ }
-
- LocalContainerEntityManagerFactoryBean
+ 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
+
+ JdoDialect
- 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.
-
+
+ LocalEntityManagerFactoryBean
- 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>
+
+ Obtaining an EntityManagerFactory from
+ JNDI
- <!-- 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>
+
+ LocalContainerEntityManagerFactoryBean
- 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>
-
- JpaDialect
+ 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
+
-
- PersistenceManagerFactory
- 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>
+
+ JpaDialect
- <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.
-
-
-
- JdoDialect
-
- 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 SqlMapClientTemplate and
+ SqlMapClientDaoSupport
+
+ 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