diff --git a/spring-framework-reference/src/classic-spring.xml b/spring-framework-reference/src/classic-spring.xml
new file mode 100644
index 00000000000..27f41258bdd
--- /dev/null
+++ b/spring-framework-reference/src/classic-spring.xml
@@ -0,0 +1,430 @@
+
+
+
+ Classic Spring Usage
+
+ This appendix discusses some classic Spring usage patterns as a
+ reference for developers maintaining legacy Spring applications. These usage
+ patterns no longer reflect the recommended way of using these features and
+ the current recommended usage is covered in the respective sections of the
+ reference manual.
+
+
+ Classic ORM usage
+
+ This section documents the classic usage patterns that you might
+ encounter in a legacy Spring application. For the currently recommended
+ usage patterns, please refer to the chapter.
+
+
+
+ Hibernate
+
+ For the currently recommended usage patterns for Hibernate see
+
+
+
+ The HibernateTemplate
+
+ The basic programming model for templating looks as follows, for
+ methods that can be part of any custom data access object or business
+ service. There are no restrictions on the implementation of the
+ surrounding object at all, it just needs to provide a Hibernate
+ SessionFactory. It can get the latter
+ from anywhere, but preferably as bean reference from a Spring IoC
+ container - via a simple
+ setSessionFactory(..) bean property setter.
+ The following snippets show a DAO definition in a Spring container,
+ referencing the above defined
+ SessionFactory, and an example for a
+ DAO method implementation.
+
+ <beans>
+
+ <bean id="myProductDao" class="product.ProductDaoImpl">
+ <property name="sessionFactory" ref="mySessionFactory"/>
+ </bean>
+
+</beans>
+
+ public class ProductDaoImpl implements ProductDao {
+
+ private HibernateTemplate hibernateTemplate;
+
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.hibernateTemplate = new HibernateTemplate(sessionFactory);
+ }
+
+ public Collection loadProductsByCategory(String category) throws DataAccessException {
+ return this.hibernateTemplate.find("from test.Product product where product.category=?", category);
+ }
+}
+
+ The HibernateTemplate class provides many
+ methods that mirror the methods exposed on the Hibernate
+ Session interface, in addition to a
+ number of convenience methods such as the one shown above. If you need
+ access to the Session to invoke methods
+ that are not exposed on the HibernateTemplate,
+ you can always drop down to a callback-based approach like so.
+
+ public class ProductDaoImpl implements ProductDao {
+
+ private HibernateTemplate hibernateTemplate;
+
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.hibernateTemplate = new HibernateTemplate(sessionFactory);
+ }
+
+ public Collection loadProductsByCategory(final String category) throws DataAccessException {
+ return this.hibernateTemplate.execute(new HibernateCallback() {
+
+ public Object doInHibernate(Session session) {
+ Criteria criteria = session.createCriteria(Product.class);
+ criteria.add(Expression.eq("category", category));
+ criteria.setMaxResults(6);
+ return criteria.list();
+ }
+ };
+ }
+}
+
+ A callback implementation effectively can be used for any
+ Hibernate data access. HibernateTemplate will
+ ensure that Session instances are
+ properly opened and closed, and automatically participate in
+ transactions. The template instances are thread-safe and reusable,
+ they can thus be kept as instance variables of the surrounding class.
+ For simple single step actions like a single find, load, saveOrUpdate,
+ or delete call, HibernateTemplate offers
+ alternative convenience methods that can replace such one line
+ callback implementations. Furthermore, Spring provides a convenient
+ HibernateDaoSupport base class that provides a
+ setSessionFactory(..) method for receiving a
+ SessionFactory, and
+ getSessionFactory() and
+ getHibernateTemplate()for use by subclasses.
+ In combination, this allows for very simple DAO implementations for
+ typical requirements:
+
+ public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
+
+ public Collection loadProductsByCategory(String category) throws DataAccessException {
+ return this.getHibernateTemplate().find(
+ "from test.Product product where product.category=?", category);
+ }
+}
+
+
+
+ Implementing Spring-based DAOs without callbacks
+
+ As alternative to using Spring's
+ HibernateTemplate to implement DAOs, data
+ access code can also be written in a more traditional fashion, without
+ wrapping the Hibernate access code in a callback, while still
+ respecting and participating in Spring's generic
+ DataAccessException hierarchy. The
+ HibernateDaoSupport base class offers methods
+ to access the current transactional
+ Session and to convert exceptions in
+ such a scenario; similar methods are also available as static helpers
+ on the SessionFactoryUtils class. Note that
+ such code will usually pass 'false' as the value of
+ the getSession(..) methods
+ 'allowCreate' argument, to enforce running within a
+ transaction (which avoids the need to close the returned
+ Session, as its lifecycle is managed by
+ the transaction).
+
+ public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
+
+ public Collection loadProductsByCategory(String category) throws DataAccessException, MyException {
+ Session session = getSession(false);
+ try {
+ Query query = session.createQuery("from test.Product product where product.category=?");
+ query.setString(0, category);
+ List result = query.list();
+ if (result == null) {
+ throw new MyException("No search results.");
+ }
+ return result;
+ }
+ catch (HibernateException ex) {
+ throw convertHibernateAccessException(ex);
+ }
+ }
+}
+
+ The advantage of such direct Hibernate access code is that it
+ allows any checked application exception to be
+ thrown within the data access code; contrast this to the
+ HibernateTemplate class which is restricted to
+ throwing only unchecked exceptions within the callback. Note that you
+ can often defer the corresponding checks and the throwing of
+ application exceptions to after the callback, which still allows
+ working with HibernateTemplate. In general, the
+ HibernateTemplate class' convenience methods
+ are simpler and more convenient for many scenarios.
+
+
+
+
+ JPA
+
+ For the currently recommended usage patterns for JPA see
+
+
+ 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
+
+ For the currently recommended usage patterns for JDO see
+
+
+ JdoTemplate and
+ JdoDaoSupport
+
+ Each JDO-based DAO will then receive the
+ PersistenceManagerFactory through
+ dependency injection. Such a DAO could be coded against plain JDO API,
+ working with the given
+ PersistenceManagerFactory, but will
+ usually rather be used with the Spring Framework's
+ JdoTemplate:
+
+ <beans>
+
+ <bean id="myProductDao" class="product.ProductDaoImpl">
+ <property name="persistenceManagerFactory" ref="myPmf"/>
+ </bean>
+
+</beans>
+
+ public class ProductDaoImpl implements ProductDao {
+
+ private JdoTemplate jdoTemplate;
+
+ public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
+ this.jdoTemplate = new JdoTemplate(pmf);
+ }
+
+ public Collection loadProductsByCategory(final String category) throws DataAccessException {
+ return (Collection) this.jdoTemplate.execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newQuery(Product.class, "category = pCategory");
+ query.declareParameters("String pCategory");
+ List result = query.execute(category);
+ // do some further stuff with the result list
+ return result;
+ }
+ });
+ }
+}
+
+ A callback implementation can effectively be used for any JDO
+ data access. JdoTemplate will ensure that
+ PersistenceManagers are properly opened and
+ closed, and automatically participate in transactions. The template
+ instances are thread-safe and reusable, they can thus be kept as
+ instance variables of the surrounding class. For simple single-step
+ actions such as a single find,
+ load, makePersistent, or
+ delete call, JdoTemplate
+ offers alternative convenience methods that can replace such one line
+ callback implementations. Furthermore, Spring provides a convenient
+ JdoDaoSupport base class that provides a
+ setPersistenceManagerFactory(..) method for
+ receiving a PersistenceManagerFactory, and
+ getPersistenceManagerFactory() and
+ getJdoTemplate() for use by subclasses. In
+ combination, this allows for very simple DAO implementations for
+ typical requirements:
+
+ public class ProductDaoImpl extends JdoDaoSupport implements ProductDao {
+
+ public Collection loadProductsByCategory(String category) throws DataAccessException {
+ return getJdoTemplate().find(
+ Product.class, "category = pCategory", "String category", new Object[] {category});
+ }
+}
+
+ As alternative to working with Spring's
+ JdoTemplate, you can also code Spring-based
+ DAOs at the JDO API level, explicitly opening and closing a
+ PersistenceManager. As elaborated in
+ the corresponding Hibernate section, the main advantage of this
+ approach is that your data access code is able to throw checked
+ exceptions. JdoDaoSupport offers a variety of
+ support methods for this scenario, for fetching and releasing a
+ transactional PersistenceManager as
+ well as for converting exceptions.
+
+
+
+
+ iBATIS
+
+ For the currently recommended usage patterns for iBATIS see
+
+
+ Using 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.
+
+
+
+
+
+ Classic Spring MVC
+
+ ...
+
+
diff --git a/spring-framework-reference/src/orm.xml b/spring-framework-reference/src/orm.xml
index a8525fa5723..4a55059f74c 100644
--- a/spring-framework-reference/src/orm.xml
+++ b/spring-framework-reference/src/orm.xml
@@ -238,150 +238,6 @@
However, that is typically not common outside of an EJB context.
-
- The HibernateTemplate
-
- The basic programming model for templating looks as follows, for
- methods that can be part of any custom data access object or business
- service. There are no restrictions on the implementation of the
- surrounding object at all, it just needs to provide a Hibernate
- SessionFactory. It can get the latter
- from anywhere, but preferably as bean reference from a Spring IoC
- container - via a simple setSessionFactory(..)
- bean property setter. The following snippets show a DAO definition in a
- Spring container, referencing the above defined
- SessionFactory, and an example for a DAO
- method implementation.
-
- <beans>
-
- <bean id="myProductDao" class="product.ProductDaoImpl">
- <property name="sessionFactory" ref="mySessionFactory"/>
- </bean>
-
-</beans>
-
- public class ProductDaoImpl implements ProductDao {
-
- private HibernateTemplate hibernateTemplate;
-
- public void setSessionFactory(SessionFactory sessionFactory) {
- this.hibernateTemplate = new HibernateTemplate(sessionFactory);
- }
-
- public Collection loadProductsByCategory(String category) throws DataAccessException {
- return this.hibernateTemplate.find("from test.Product product where product.category=?", category);
- }
-}
-
- The HibernateTemplate class provides many
- methods that mirror the methods exposed on the Hibernate
- Session interface, in addition to a
- number of convenience methods such as the one shown above. If you need
- access to the Session to invoke methods
- that are not exposed on the HibernateTemplate,
- you can always drop down to a callback-based approach like so.
-
- public class ProductDaoImpl implements ProductDao {
-
- private HibernateTemplate hibernateTemplate;
-
- public void setSessionFactory(SessionFactory sessionFactory) {
- this.hibernateTemplate = new HibernateTemplate(sessionFactory);
- }
-
- public Collection loadProductsByCategory(final String category) throws DataAccessException {
- return this.hibernateTemplate.execute(new HibernateCallback() {
-
- public Object doInHibernate(Session session) {
- Criteria criteria = session.createCriteria(Product.class);
- criteria.add(Expression.eq("category", category));
- criteria.setMaxResults(6);
- return criteria.list();
- }
- };
- }
-}
-
- A callback implementation effectively can be used for any
- Hibernate data access. HibernateTemplate will
- ensure that Session instances are
- properly opened and closed, and automatically participate in
- transactions. The template instances are thread-safe and reusable, they
- can thus be kept as instance variables of the surrounding class. For
- simple single step actions like a single find, load, saveOrUpdate, or
- delete call, HibernateTemplate offers alternative
- convenience methods that can replace such one line callback
- implementations. Furthermore, Spring provides a convenient
- HibernateDaoSupport base class that provides a
- setSessionFactory(..) method for receiving a
- SessionFactory, and
- getSessionFactory() and
- getHibernateTemplate()for use by subclasses. In
- combination, this allows for very simple DAO implementations for typical
- requirements:
-
- public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
-
- public Collection loadProductsByCategory(String category) throws DataAccessException {
- return this.getHibernateTemplate().find(
- "from test.Product product where product.category=?", category);
- }
-}
-
-
-
- Implementing Spring-based DAOs without callbacks
-
- As alternative to using Spring's
- HibernateTemplate to implement DAOs, data access
- code can also be written in a more traditional fashion, without wrapping
- the Hibernate access code in a callback, while still respecting and
- participating in Spring's generic
- DataAccessException hierarchy. The
- HibernateDaoSupport base class offers methods to
- access the current transactional Session
- and to convert exceptions in such a scenario; similar methods are also
- available as static helpers on the
- SessionFactoryUtils class. Note that such code
- will usually pass 'false' as the value of the
- getSession(..) methods
- 'allowCreate' argument, to enforce running within a
- transaction (which avoids the need to close the returned
- Session, as its lifecycle is managed by
- the transaction).
-
- public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
-
- public Collection loadProductsByCategory(String category) throws DataAccessException, MyException {
- Session session = getSession(false);
- try {
- Query query = session.createQuery("from test.Product product where product.category=?");
- query.setString(0, category);
- List result = query.list();
- if (result == null) {
- throw new MyException("No search results.");
- }
- return result;
- }
- catch (HibernateException ex) {
- throw convertHibernateAccessException(ex);
- }
- }
-}
-
- The advantage of such direct Hibernate access code is that it
- allows any checked application exception to be
- thrown within the data access code; contrast this to the
- HibernateTemplate class which is restricted to
- throwing only unchecked exceptions within the callback. Note that you
- can often defer the corresponding checks and the throwing of application
- exceptions to after the callback, which still allows working with
- HibernateTemplate. In general, the
- HibernateTemplate class' convenience methods are
- simpler and more convenient for many scenarios.
-
-
Implementing DAOs based on plain Hibernate 3 API
@@ -950,1436 +806,1204 @@
-
- JDO
-
- Spring supports the standard JDO 2.0/2.1 API as data access
- strategy, following the same style as the Hibernate support. The
- corresponding integration classes reside in the
- org.springframework.orm.jdo package.
-
-
- PersistenceManagerFactory
- setup
-
- Spring provides a
- LocalPersistenceManagerFactoryBean class that
- allows for defining a local JDO
- PersistenceManagerFactory within a Spring
- application context:
+
+ JPA
- <beans>
+ Spring JPA (available under the
+ org.springframework.orm.jpa package) offers
+ comprehensive support for the Java
+ Persistence API in a similar manner to the integration with
+ Hibernate or JDO, while being aware of the underlying implementation in
+ order to provide additional features.
- <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
- <property name="configLocation" value="classpath:kodo.properties"/>
- </bean>
+
+ JPA setup in a Spring environment
-</beans>
+ Spring JPA offers three ways of setting up JPA
+ EntityManagerFactory:
- Alternatively, a
- PersistenceManagerFactory can also be set
- up through direct instantiation of a
- PersistenceManagerFactory implementation
- class. A JDO PersistenceManagerFactory
- implementation class is supposed to follow the JavaBeans pattern, just
- like a JDBC DataSource implementation
- class, which is a natural fit for a Spring bean definition. This setup
- style usually supports a Spring-defined JDBC
- DataSource, passed into the
- "connectionFactory" property. For example, for the open source JDO
- implementation JPOX ():
+
+ LocalEntityManagerFactoryBean
- <beans>
+ The LocalEntityManagerFactoryBean creates
+ an EntityManagerFactory suitable for
+ environments which solely use JPA for data access. The factory bean
+ will use the JPA PersistenceProvider
+ autodetection mechanism (according to JPA's Java SE bootstrapping)
+ and, in most cases, requires only the persistence unit name to be
+ specified:
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
- <property name="driverClassName" value="${jdbc.driverClassName}"/>
- <property name="url" value="${jdbc.url}"/>
- <property name="username" value="${jdbc.username}"/>
- <property name="password" value="${jdbc.password}"/>
- </bean>
+ <beans>
- <bean id="myPmf" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close">
- <property name="connectionFactory" ref="dataSource"/>
- <property name="nontransactionalRead" value="true"/>
- </bean>
+ <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
+ <property name="persistenceUnitName" value="myPersistenceUnit"/>
+ </bean>
</beans>
- A JDO PersistenceManagerFactory can
- also be set up in the JNDI environment of a J2EE application server,
- usually through the JCA connector provided by the particular JDO
- implementation. Spring's standard
- JndiObjectFactoryBean can be used to retrieve and
- expose such a PersistenceManagerFactory.
- However, outside an EJB context, there is often no compelling benefit in
- holding the PersistenceManagerFactory in
- JNDI: only choose such setup for a good reason. See "container resources
- versus local resources" in the Hibernate section for a discussion; the
- arguments there apply to JDO as well.
-
+ This is the simplest but also most limited form of JPA
+ deployment. There is no way to link to an existing JDBC
+ DataSource and no support for global
+ transactions, for example. Furthermore, weaving (byte-code
+ transformation) of persistent classes is provider-specific, often
+ requiring a specific JVM agent to specified on startup. All in all,
+ this option is only really sufficient for standalone applications and
+ test environments (which is exactly what the JPA specification
+ designed it for).
-
- JdoTemplate and
- JdoDaoSupport
+ Only use this option in simple deployment environments
+ like standalone applications and integration tests.
+
- Each JDO-based DAO will then receive the
- PersistenceManagerFactory through
- dependency injection. Such a DAO could be coded against plain JDO API,
- working with the given
- PersistenceManagerFactory, but will
- usually rather be used with the Spring Framework's
- JdoTemplate:
+
+ Obtaining an EntityManagerFactory from
+ JNDI
- <beans>
-
- <bean id="myProductDao" class="product.ProductDaoImpl">
- <property name="persistenceManagerFactory" ref="myPmf"/>
- </bean>
-
-</beans>
+ Obtaining an EntityManagerFactory
+ from JNDI (for example in a Java EE 5 environment), is just a matter
+ of changing the XML configuration:
- public class ProductDaoImpl implements ProductDao {
-
- private JdoTemplate jdoTemplate;
+ <beans>
- public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
- this.jdoTemplate = new JdoTemplate(pmf);
- }
+ <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
- public Collection loadProductsByCategory(final String category) throws DataAccessException {
- return (Collection) this.jdoTemplate.execute(new JdoCallback() {
- public Object doInJdo(PersistenceManager pm) throws JDOException {
- Query query = pm.newQuery(Product.class, "category = pCategory");
- query.declareParameters("String pCategory");
- List result = query.execute(category);
- // do some further stuff with the result list
- return result;
- }
- });
- }
-}
+</beans>
- A callback implementation can effectively be used for any JDO data
- access. JdoTemplate will ensure that
- PersistenceManagers are properly opened and
- closed, and automatically participate in transactions. The template
- instances are thread-safe and reusable, they can thus be kept as
- instance variables of the surrounding class. For simple single-step
- actions such as a single find,
- load, makePersistent, or
- delete call, JdoTemplate
- offers alternative convenience methods that can replace such one line
- callback implementations. Furthermore, Spring provides a convenient
- JdoDaoSupport base class that provides a
- setPersistenceManagerFactory(..) method for receiving
- a PersistenceManagerFactory, and
- getPersistenceManagerFactory() and
- getJdoTemplate() for use by subclasses. In
- combination, this allows for very simple DAO implementations for typical
- requirements:
-
- public class ProductDaoImpl extends JdoDaoSupport implements ProductDao {
-
- public Collection loadProductsByCategory(String category) throws DataAccessException {
- return getJdoTemplate().find(
- Product.class, "category = pCategory", "String category", new Object[] {category});
- }
-}
+ This assumes standard Java EE 5 bootstrapping, with the Java EE
+ server autodetecting persistence units (i.e.
+ META-INF/persistence.xml files in application jars)
+ and persistence-unit-ref entries in the Java EE
+ deployment descriptor (e.g. web.xml) defining
+ environment naming context locations for those persistence
+ units.
- As alternative to working with Spring's
- JdoTemplate, you can also code Spring-based DAOs
- at the JDO API level, explicitly opening and closing a
- PersistenceManager. As elaborated in the
- corresponding Hibernate section, the main advantage of this approach is
- that your data access code is able to throw checked exceptions.
- JdoDaoSupport offers a variety of support methods
- for this scenario, for fetching and releasing a transactional
- PersistenceManager as well as for
- converting exceptions.
-
+ In such a scenario, the entire persistence unit deployment,
+ including the weaving (byte-code transformation) of persistent
+ classes, is up to the Java EE server. The JDBC
+ DataSource is defined through a JNDI
+ location in the META-INF/persistence.xml file;
+ EntityManager transactions are integrated with the server's JTA
+ subsystem. Spring merely uses the obtained
+ EntityManagerFactory, passing it on to
+ application objects via dependency injection, and managing
+ transactions for it (typically through
+ JtaTransactionManager).
-
- Implementing DAOs based on the plain JDO API
+ Note that, in case of multiple persistence units used in the
+ same application, the bean names of such a JNDI-retrieved persistence
+ units should match the persistence unit names that the application
+ uses to refer to them (e.g. in @PersistenceUnit and
+ @PersistenceContext annotations).
- DAOs can also be written against plain JDO API, without any Spring
- dependencies, directly using an injected
- PersistenceManagerFactory. A
- corresponding DAO implementation looks like as follows:
+ Use this option when deploying to a Java EE 5 server.
+ Check your server's documentation on how to deploy a custom JPA
+ provider into your server, allowing for a different provider than the
+ server's default.
+
- public class ProductDaoImpl implements ProductDao {
+
+ LocalContainerEntityManagerFactoryBean
- private PersistenceManagerFactory persistenceManagerFactory;
+ The
+ LocalContainerEntityManagerFactoryBean gives
+ full control over EntityManagerFactory
+ configuration and is appropriate for environments where fine-grained
+ customization is required. The
+ LocalContainerEntityManagerFactoryBean will
+ create a PersistenceUnitInfo based on
+ the persistence.xml file, the supplied
+ dataSourceLookup strategy and the specified
+ loadTimeWeaver. It is thus possible to work with
+ custom DataSources outside of JNDI and to control the weaving
+ process.
- public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
- this.persistenceManagerFactory = pmf;
- }
+ <beans>
+
+ <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+ <property name="dataSource" ref="someDataSource"/>
+ <property name="loadTimeWeaver">
+ <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
+ </property>
+ </bean>
+
+</beans>
- public Collection loadProductsByCategory(String category) {
- PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
- try {
- Query query = pm.newQuery(Product.class, "category = pCategory");
- query.declareParameters("String pCategory");
- return query.execute(category);
- }
- finally {
- pm.close();
- }
- }
-}
+ A typical persistence.xml file looks as
+ follows:
- As the above DAO still follows the Dependency Injection pattern,
- it still fits nicely into a Spring container, just like it would if
- coded against Spring's JdoTemplate:
+ <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
- <beans>
+ <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
+ <mapping-file>META-INF/orm.xml</mapping-file>
+ <exclude-unlisted-classes/>
+ </persistence-unit>
- <bean id="myProductDao" class="product.ProductDaoImpl">
- <property name="persistenceManagerFactory" ref="myPmf"/>
- </bean>
+</persistence>
-</beans>
-
- The main issue with such DAOs is that they always get a new
- PersistenceManager from the factory. To
- still access a Spring-managed transactional
- PersistenceManager, consider defining a
- TransactionAwarePersistenceManagerFactoryProxy
- (as included in Spring) in front of your target
- PersistenceManagerFactory, passing the
- proxy into your DAOs.
-
- <beans>
-
- <bean id="myPmfProxy"
- class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
- <property name="targetPersistenceManagerFactory" ref="myPmf"/>
- </bean>
-
- <bean id="myProductDao" class="product.ProductDaoImpl">
- <property name="persistenceManagerFactory" ref="myPmfProxy"/>
- </bean>
-
-</beans>
-
- Your data access code will then receive a transactional
- PersistenceManager (if any) from the
- PersistenceManagerFactory.getPersistenceManager()
- method that it calls. The latter method call goes through the proxy,
- which will first check for a current transactional
- PersistenceManager before getting a new
- one from the factory. close() calls on the
- PersistenceManager will be ignored in
- case of a transactional
- PersistenceManager.
-
- If your data access code will always run within an active
- transaction (or at least within active transaction synchronization), it
- is safe to omit the PersistenceManager.close()
- call and thus the entire finally block, which you
- might prefer to keep your DAO implementations concise:
-
- public class ProductDaoImpl implements ProductDao {
-
- private PersistenceManagerFactory persistenceManagerFactory;
-
- public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
- this.persistenceManagerFactory = pmf;
- }
-
- public Collection loadProductsByCategory(String category) {
- PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
- Query query = pm.newQuery(Product.class, "category = pCategory");
- query.declareParameters("String pCategory");
- return query.execute(category);
- }
-}
-
- With such DAOs that rely on active transactions, it is recommended
- to enforce active transactions through turning
- TransactionAwarePersistenceManagerFactoryProxy's
- "allowCreate" flag off:
-
- <beans>
-
- <bean id="myPmfProxy"
- class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
- <property name="targetPersistenceManagerFactory" ref="myPmf"/>
- <property name="allowCreate" value="false"/>
- </bean>
-
- <bean id="myProductDao" class="product.ProductDaoImpl">
- <property name="persistenceManagerFactory" ref="myPmfProxy"/>
- </bean>
-
-</beans>
-
- The main advantage of this DAO style is that it depends on JDO API
- only; no import of any Spring class is required. This is of course
- appealing from a non-invasiveness perspective, and might feel more
- natural to JDO developers.
-
- However, the DAO throws plain
- JDOException (which is unchecked, so does
- not have to be declared or caught), which means that callers can only
- treat exceptions as generally fatal - unless they want to depend on
- JDO's own exception structure. Catching specific causes such as an
- optimistic locking failure is not possible without tying the caller to
- the implementation strategy. This tradeoff might be acceptable to
- applications that are strongly JDO-based and/or do not need any special
- exception treatment.
-
- In summary: DAOs can be implemented based on plain JDO API, while
- still being able to participate in Spring-managed transactions. This
- might in particular appeal to people already familiar with JDO, feeling
- more natural to them. However, such DAOs will throw plain
- JDOException; conversion to Spring's
- DataAccessException would have to happen
- explicitly (if desired).
-
-
-
- Transaction management
-
- To execute service operations within transactions, you can use
- Spring's common declarative transaction facilities. For example:
-
- <?xml version="1.0" encoding="UTF-8"?>
-<beans
- xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
-
- <bean id="myTxManager" class="org.springframework.orm.jdo.JdoTransactionManager">
- <property name="persistenceManagerFactory" ref="myPmf"/>
- </bean>
-
- <bean id="myProductService" class="product.ProductServiceImpl">
- <property name="productDao" ref="myProductDao"/>
- </bean>
-
- <tx:advice id="txAdvice" transaction-manager="txManager">
- <tx:attributes>
- <tx:method name="increasePrice*" propagation="REQUIRED"/>
- <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
- <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
- </tx:attributes>
- </tx:advice>
-
- <aop:config>
- <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/>
- <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
- </aop:config>
-
-</beans>
-
- Note that JDO requires an active transaction when modifying a
- persistent object. There is no concept like a non-transactional flush in
- JDO, in contrast to Hibernate. For this reason, the chosen JDO
- implementation needs to be set up for a specific environment: in
- particular, it needs to be explicitly set up for JTA synchronization, to
- detect an active JTA transaction itself. This is not necessary for local
- transactions as performed by Spring's
- JdoTransactionManager, but it is necessary for
- participating in JTA transactions (whether driven by Spring's
- JtaTransactionManager or by EJB CMT / plain
- JTA).
-
- JdoTransactionManager is capable of
- exposing a JDO transaction to JDBC access code that accesses the same
- JDBC DataSource, provided that the
- registered JdoDialect supports retrieval of the
- underlying JDBC Connection. This is the
- case for JDBC-based JDO 2.0 implementations by default.
-
-
-
- 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.
-
-
-
-
- iBATIS SQL Maps
-
- The iBATIS support in the Spring Framework much resembles the JDBC /
- Hibernate support in that it supports the same template style programming
- and just as with JDBC or Hibernate, the iBATIS support works with Spring's
- exception hierarchy and let's you enjoy the all IoC features Spring
- has.
-
- Transaction management can be handled through Spring's standard
- facilities. There are no special transaction strategies for iBATIS, as
- there is no special transactional resource involved other than a JDBC
- Connection. Hence, Spring's standard JDBC
- DataSourceTransactionManager or
- JtaTransactionManager are perfectly
- sufficient.
-
-
- Spring does actually support both iBatis 1.x and 2.x. However,
- only support for iBatis 2.x is actually shipped with the core Spring
- distribution. The iBatis 1.x support classes were moved to the Spring
- Modules project as of Spring 2.0, and you are directed there for
- documentation.
-
-
-
- Setting up the SqlMapClient
-
- If we want to map the previous Account class with iBATIS 2.x we
- need to create the following SQL map
- 'Account.xml':
-
- <sqlMap namespace="Account">
-
- <resultMap id="result" class="examples.Account">
- <result property="name" column="NAME" columnIndex="1"/>
- <result property="email" column="EMAIL" columnIndex="2"/>
- </resultMap>
-
- <select id="getAccountByEmail" resultMap="result">
- select ACCOUNT.NAME, ACCOUNT.EMAIL
- from ACCOUNT
- where ACCOUNT.EMAIL = #value#
- </select>
-
- <insert id="insertAccount">
- insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
- </insert>
-
-</sqlMap>
-
- The configuration file for iBATIS 2 looks like this:
-
- <sqlMapConfig>
-
- <sqlMap resource="example/Account.xml"/>
-
-</sqlMapConfig>
-
- Remember that iBATIS loads resources from the class path, so be
- sure to add the 'Account.xml' file to the class
- path.
-
- We can use the SqlMapClientFactoryBean in
- the Spring container. Note that with iBATIS SQL Maps 2.x, the JDBC
- DataSource is usually specified on the
- SqlMapClientFactoryBean, which enables lazy
- loading.
+ NOTE: The "exclude-unlisted-classes" element always
+ indicates that NO scanning for annotated entity classes is supposed to
+ happen, in order to support the
+ <exclude-unlisted-classes/> shortcut. This is
+ in line with the JPA specification (which suggests that shortcut) but
+ unfortunately in conflict with the JPA XSD (which implies "false" for
+ that shortcut). As a consequence,
+ "<exclude-unlisted-classes> false
+ </exclude-unlisted-classes/>" is not supported! Simply
+ omit the "exclude-unlisted-classes" element if you would like entity
+ class scanning to actually happen.
- <beans>
+ This is the most powerful JPA setup option, allowing for
+ flexible local configuration within the application. It supports links
+ to an existing JDBC DataSource,
+ supports both local and global transactions, etc. However, it also
+ imposes requirements onto the runtime environment, such as the
+ availability of a weaving-capable ClassLoader if the persistence
+ provider demands byte-code transformation.
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
- <property name="driverClassName" value="${jdbc.driverClassName}"/>
- <property name="url" value="${jdbc.url}"/>
- <property name="username" value="${jdbc.username}"/>
- <property name="password" value="${jdbc.password}"/>
- </bean>
+ Note that this option may conflict with the built-in JPA
+ capabilities of a Java EE 5 server. So when running in a full Java EE
+ 5 environment, consider obtaining your
+ EntityManagerFactory from JNDI.
+ Alternatively, specify a custom "persistenceXmlLocation" on your
+ LocalContainerEntityManagerFactoryBean
+ definition, e.g. "META-INF/my-persistence.xml", and only include a
+ descriptor with that name in your application jar files. Since the
+ Java EE 5 server will only look for default
+ META-INF/persistence.xml files, it will ignore such
+ custom persistence units and hence avoid conflicts with a
+ Spring-driven JPA setup upfront. (This applies to Resin 3.1, for
+ example.)
- <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="configLocation" value="WEB-INF/sqlmap-config.xml"/>
- <property name="dataSource" ref="dataSource"/>
- </bean>
+ Use this option for full JPA capabilities in a
+ Spring-based application environment. This includes web containers
+ such as Tomcat as well as standalone applications and integration
+ tests with sophisticated persistence requirements.
-</beans>
-
+
+ When is load-time weaving required?
-
- Using SqlMapClientTemplate and
- SqlMapClientDaoSupport
+ Not all JPA providers impose the need of a JVM agent
+ (Hibernate being an example). If your provider does not require an
+ agent or you have other alternatives (for example applying
+ enhancements at build time through a custom compiler or an ant task)
+ the load-time weaver should not be
+ used.
+
- The SqlMapClientDaoSupport class offers a
- supporting class similar to the SqlMapDaoSupport.
- We extend it to implement our DAO:
+ The LoadTimeWeaver interface is a
+ Spring-provided class that allows JPA
+ ClassTransformer instances to be
+ plugged in a specific manner depending on the environment (web
+ container/application server). Hooking
+ ClassTransformers through a Java 5 agent
+ is typically not efficient - the agents work against the
+ entire virtual machine and inspect
+ every class that is loaded - something that is
+ typically undesirable in a production server enviroment.
- public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {
+ Spring provides a number of
+ LoadTimeWeaver implementations for
+ various environments, allowing
+ ClassTransformer instances to be
+ applied only per ClassLoader and not per
+ VM.
- public Account getAccount(String email) throws DataAccessException {
- return (Account) getSqlMapClientTemplate().queryForObject("getAccountByEmail", email);
- }
+ The following sections will discuss typical JPA weaving setup on
+ Tomcat as well as using Spring's VM agent. See the AOP chapter section
+ entitled for details on how to
+ set up general load-time weaving, covering Tomcat and the VM agent as
+ well as WebLogic, OC4J, GlassFish and Resin.
- public void insertAccount(Account account) throws DataAccessException {
- getSqlMapClientTemplate().update("insertAccount", account);
- }
-}
+
+ Tomcat load-time weaving setup (5.0+)
- In the DAO, we use the pre-configured
- SqlMapClientTemplate to execute the queries,
- after setting up the SqlMapAccountDao in the
- application context and wiring it with our
- SqlMapClient instance:
+ Apache Tomcat's
+ default ClassLoader does not support class transformation but allows
+ custom ClassLoaders to be used. Spring offers the
+ TomcatInstrumentableClassLoader (inside the
+ org.springframework.instrument.classloading.tomcat
+ package) which extends the Tomcat ClassLoader
+ (WebappClassLoader) and allows JPA
+ ClassTransformer instances to 'enhance' all
+ classes loaded by it. In short, JPA transformers will be applied
+ only inside a specific web application (which uses the
+ TomcatInstrumentableClassLoader).
- <beans>
+ In order to use the custom ClassLoader on:
- <bean id="accountDao" class="example.SqlMapAccountDao">
- <property name="sqlMapClient" ref="sqlMapClient"/>
- </bean>
+
+
+ Tomcat 5.0.x/5.5.x
+
-</beans>
+
+
+ Copy spring-tomcat-weaver.jar into
+ $CATALINA_HOME/server/lib (where
+ $CATALINA_HOME represents the root of the
+ Tomcat installation).
+
- Note that a SqlMapTemplate instance could
- also be created manually, passing in the SqlMapClient
- as constructor argument. The SqlMapClientDaoSupport
- base class simply pre-initializes a
- SqlMapClientTemplate instance for us.
+
+ Instruct Tomcat to use the custom ClassLoader (instead
+ of the default one) by editing the web application context
+ file:
- The SqlMapClientTemplate also offers a
- generic execute method, taking a custom
- SqlMapClientCallback implementation as argument. This
- can, for example, be used for batching:
+ <Context path="/myWebApp" docBase="/my/webApp/location">
+ <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
+</Context>
- public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {
+ Tomcat 5.0.x and 5.5.x series support several context
+ locations: server configuration file
+ ($CATALINA_HOME/conf/server.xml), the
+ default context configuration
+ ($CATALINA_HOME/conf/context.xml) that
+ affects all deployed web applications and per-webapp
+ configurations, deployed on the server
+ ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml)
+ side or along with the webapp
+ (your-webapp.war/META-INF/context.xml).
+ For efficiency, inside the web-app configuration style is
+ recommended since only applications which use JPA will use the
+ custom ClassLoader. See the Tomcat 5.x documentation
+ for more details about available context locations.
- public void insertAccount(Account account) throws DataAccessException {
- getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
- public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
- executor.startBatch();
- executor.update("insertAccount", account);
- executor.update("insertAddress", account.getAddress());
- executor.executeBatch();
- }
- });
- }
-}
+ Note that versions prior to 5.5.20 contained a bug in
+ the XML configuration parsing preventing usage of
+ Loader tag inside
+ server.xml (no matter if a ClassLoader is
+ specified or not (be it the official or a custom one). See
+ Tomcat's bugzilla for more
+ details.
- In general, any combination of operations offered by the native
- SqlMapExecutor API can be used in such a callback.
- Any SQLException thrown will automatically get
- converted to Spring's generic DataAccessException
- hierarchy.
-
+ If you are using Tomcat 5.5.20+ you can set
+ useSystemClassLoaderAsParent to
+ false to fix the problem: <Context path="/myWebApp" docBase="/my/webApp/location">
+ <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
+ useSystemClassLoaderAsParent="false"/>
+</Context>
+
+
-
- Implementing DAOs based on plain iBATIS API
+
+ Tomcat 6.0.x
+
- DAOs can also be written against plain iBATIS API, without any
- Spring dependencies, directly using an injected
- SqlMapClient. A corresponding DAO implementation
- looks like as follows:
+
+
+ Copy spring-tomcat-weaver.jar into
+ $CATALINA_HOME/lib (where
+ $CATALINA_HOME represents the root of the
+ Tomcat installation).
+
- public class SqlMapAccountDao implements AccountDao {
-
- private SqlMapClient sqlMapClient;
-
- public void setSqlMapClient(SqlMapClient sqlMapClient) {
- this.sqlMapClient = sqlMapClient;
- }
+
+ Instruct Tomcat to use the custom ClassLoader (instead
+ of the default one) by editing the web application context
+ file:
- public Account getAccount(String email) {
- try {
- return (Account) this.sqlMapClient.queryForObject("getAccountByEmail", email);
- }
- catch (SQLException ex) {
- throw new MyDaoException(ex);
- }
- }
+ <Context path="/myWebApp" docBase="/my/webApp/location">
+ <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
+</Context>
- public void insertAccount(Account account) throws DataAccessException {
- try {
- this.sqlMapClient.update("insertAccount", account);
- }
- catch (SQLException ex) {
- throw new MyDaoException(ex);
- }
- }
-}
+ Tomcat 6.0.x (similar to 5.0.x/5.5.x) series support
+ several context locations: server configuration file
+ ($CATALINA_HOME/conf/server.xml), the
+ default context configuration
+ ($CATALINA_HOME/conf/context.xml) that
+ affects all deployed web applications and per-webapp
+ configurations, deployed on the server
+ ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml)
+ side or along with the webapp
+ (your-webapp.war/META-INF/context.xml).
+ For efficiency, inside the web-app configuration style is
+ recommended since only applications which use JPA will use the
+ custom ClassLoader. See the Tomcat 5.x documentation
+ for more details about available context locations.
+
+
+
- In such a scenario, the SQLException thrown by
- the iBATIS API needs to be handled in a custom fashion: usually,
- wrapping it in your own application-specific DAO exception. Wiring in
- the application context would still look like before, due to the fact
- that the plain iBATIS-based DAO still follows the Dependency Injection
- pattern:
+ The last step required on all Tomcat versions, is to use the
+ appropriate the LoadTimeWeaver when
+ configuring
+ LocalContainerEntityManagerFactoryBean:
- <beans>
+ <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+ <property name="loadTimeWeaver">
+ <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
+ </property>
+</bean>
- <bean id="accountDao" class="example.SqlMapAccountDao">
- <property name="sqlMapClient" ref="sqlMapClient"/>
- </bean>
+ Using this technique, JPA applications relying on
+ instrumentation, can run in Tomcat without the need of an agent.
+ This is important especially when hosting applications which rely on
+ different JPA implementations since the JPA transformers are applied
+ only at ClassLoader level and thus, are isolated from each
+ other.
-</beans>
-
-
+
+ If TopLink Essentials is being used a JPA provider under
+ Tomcat, please place the toplink-essentials jar under
+ $CATALINA_HOME/shared/lib folder instead of
+ your war.
+
+
-
- JPA
+
+ General load-time weaving using the VM agent
- Spring JPA (available under the
- org.springframework.orm.jpa package) offers
- comprehensive support for the Java
- Persistence API in a similar manner to the integration with
- Hibernate or JDO, while being aware of the underlying implementation in
- order to provide additional features.
+ For environments where class instrumentation is required but
+ are not supported by the existing LoadTimeWeaver implementations, a
+ JDK agent can be the only solution. For such cases, Spring provides
+ InstrumentationLoadTimeWeaver which requires
+ a Spring-specific (but very general) VM agent (spring-agent.jar):
-
- JPA setup in a Spring environment
+ <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+ <property name="loadTimeWeaver">
+ <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
+ </property>
+</bean>
- Spring JPA offers three ways of setting up JPA
- EntityManagerFactory:
+ Note that the virtual machine has to be started with the
+ Spring agent, by supplying the following JVM options:
-
- LocalEntityManagerFactoryBean
+ -javaagent:/path/to/spring-agent.jar
+
- The LocalEntityManagerFactoryBean creates
- an EntityManagerFactory suitable for
- environments which solely use JPA for data access. The factory bean
- will use the JPA PersistenceProvider
- autodetection mechanism (according to JPA's Java SE bootstrapping)
- and, in most cases, requires only the persistence unit name to be
- specified:
+
+ Context-wide load-time weaver setup
- <beans>
+ Since Spring 2.5, a context-wide
+ LoadTimeWeaver can be configured
+ using the context:load-time-weaver configuration
+ element. Such a 'global' weaver will be picked up by all JPA
+ LocalContainerEntityManagerFactoryBeans
+ automatically.
- <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
- <property name="persistenceUnitName" value="myPersistenceUnit"/>
- </bean>
+ This is the preferred way of setting up a load-time weaver,
+ delivering autodetection of the platform (WebLogic, OC4J, GlassFish,
+ Tomcat, Resin, VM agent) as well as automatic propagation of the
+ weaver to all weaver-aware beans.
-</beans>
+ <context:load-time-weaver/>
- This is the simplest but also most limited form of JPA
- deployment. There is no way to link to an existing JDBC
- DataSource and no support for global
- transactions, for example. Furthermore, weaving (byte-code
- transformation) of persistent classes is provider-specific, often
- requiring a specific JVM agent to specified on startup. All in all,
- this option is only really sufficient for standalone applications and
- test environments (which is exactly what the JPA specification
- designed it for).
+<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+ ...
+</bean>
- Only use this option in simple deployment environments
- like standalone applications and integration tests.
+ See the section entitled
+ for details on how to set up general load-time weaving, covering
+ Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and
+ Resin.
+
-
- Obtaining an EntityManagerFactory from
- JNDI
-
- Obtaining an EntityManagerFactory
- from JNDI (for example in a Java EE 5 environment), is just a matter
- of changing the XML configuration:
+
+ Dealing with multiple persistence units
- <beans>
+ For applications that rely on multiple persistence units
+ locations (stored in various jars in the classpath for example),
+ Spring offers the
+ PersistenceUnitManager to act as a
+ central repository and avoid the (potentially expensive) persistence
+ units discovery process. The default implementation allows multiple
+ locations to be specified (by default, the classpath is searched for
+ 'META-INF/persistence.xml' files) which are
+ parsed and later on retrieved through the persistence unit
+ name:
- <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
+ <bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
+ <property name="persistenceXmlLocation">
+ <list>
+ <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
+ <value>classpath:/my/package/**/custom-persistence.xml</value>
+ <value>classpath*:META-INF/persistence.xml</value>
+ </list>
+ </property>
+ <property name="dataSources">
+ <map>
+ <entry key="localDataSource" value-ref="local-db"/>
+ <entry key="remoteDataSource" value-ref="remote-db"/>
+ </map>
+ </property>
+ <!-- if no datasource is specified, use this one -->
+ <property name="defaultDataSource" ref="remoteDataSource"/>
+</bean>
-</beans>
+<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+ <property name="persistenceUnitManager" ref="pum"/>
+</bean>
- This assumes standard Java EE 5 bootstrapping, with the Java EE
- server autodetecting persistence units (i.e.
- META-INF/persistence.xml files in application jars)
- and persistence-unit-ref entries in the Java EE
- deployment descriptor (e.g. web.xml) defining
- environment naming context locations for those persistence
- units.
+ Note that the default implementation allows customization of the
+ persistence unit infos before feeding them to the JPA provider
+ declaratively through its properties (which affect
+ all hosted units) or programmatically, through
+ the PersistenceUnitPostProcessor (which
+ allows persistence unit selection). If no
+ PersistenceUnitManager is specified,
+ one will be created and used internally by
+ LocalContainerEntityManagerFactoryBean.
+
+
- In such a scenario, the entire persistence unit deployment,
- including the weaving (byte-code transformation) of persistent
- classes, is up to the Java EE server. The JDBC
- DataSource is defined through a JNDI
- location in the META-INF/persistence.xml file;
- EntityManager transactions are integrated with the server's JTA
- subsystem. Spring merely uses the obtained
- EntityManagerFactory, passing it on to
- application objects via dependency injection, and managing
- transactions for it (typically through
- JtaTransactionManager).
+
+ Implementing DAOs based on plain JPA
- Note that, in case of multiple persistence units used in the
- same application, the bean names of such a JNDI-retrieved persistence
- units should match the persistence unit names that the application
- uses to refer to them (e.g. in @PersistenceUnit and
- @PersistenceContext annotations).
+
+ While EntityManagerFactory
+ instances are thread-safe,
+ EntityManager instances are not. The
+ injected JPA EntityManager behave just
+ like an EntityManager fetched from an
+ application server's JNDI environment, as defined by the JPA
+ specification. It will delegate all calls to the current transactional
+ EntityManager, if any; else, it will
+ fall back to a newly created
+ EntityManager per operation, making it
+ thread-safe.
+
- Use this option when deploying to a Java EE 5 server.
- Check your server's documentation on how to deploy a custom JPA
- provider into your server, allowing for a different provider than the
- server's default.
-
+ It is possible to write code against the plain JPA without using
+ any Spring dependencies, using an injected
+ EntityManagerFactory or
+ EntityManager. Note that Spring can
+ understand @PersistenceUnit and
+ @PersistenceContext annotations both at
+ field and method level if a
+ PersistenceAnnotationBeanPostProcessor is
+ enabled. A corresponding DAO implementation might look like this:
-
- LocalContainerEntityManagerFactoryBean
+ public class ProductDaoImpl implements ProductDao {
- The
- LocalContainerEntityManagerFactoryBean gives
- full control over EntityManagerFactory
- configuration and is appropriate for environments where fine-grained
- customization is required. The
- LocalContainerEntityManagerFactoryBean will
- create a PersistenceUnitInfo based on
- the persistence.xml file, the supplied
- dataSourceLookup strategy and the specified
- loadTimeWeaver. It is thus possible to work with
- custom DataSources outside of JNDI and to control the weaving
- process.
+ private EntityManagerFactory emf;
- <beans>
-
- <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- <property name="dataSource" ref="someDataSource"/>
- <property name="loadTimeWeaver">
- <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
- </property>
- </bean>
-
-</beans>
+ @PersistenceUnit
+ public void setEntityManagerFactory(EntityManagerFactory emf) {
+ this.emf = emf;
+ }
- A typical persistence.xml file looks as
- follows:
+ public Collection loadProductsByCategory(String category) {
+ EntityManager em = this.emf.createEntityManager();
+ try {
+ Query query = em.createQuery("from Product as p where p.category = ?1");
+ query.setParameter(1, category);
+ return query.getResultList();
+ }
+ finally {
+ if (em != null) {
+ em.close();
+ }
+ }
+ }
+}
- <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+ The DAO above has no dependency on Spring and still fits nicely
+ into a Spring application context, just like it would if coded against
+ Spring's JpaTemplate. Moreover, the DAO takes
+ advantage of annotations to require the injection of the default
+ EntityManagerFactory:
- <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
- <mapping-file>META-INF/orm.xml</mapping-file>
- <exclude-unlisted-classes/>
- </persistence-unit>
+ <beans>
-</persistence>
+ <!-- bean post-processor for JPA annotations -->
+ <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
- NOTE: The "exclude-unlisted-classes" element always
- indicates that NO scanning for annotated entity classes is supposed to
- happen, in order to support the
- <exclude-unlisted-classes/> shortcut. This is
- in line with the JPA specification (which suggests that shortcut) but
- unfortunately in conflict with the JPA XSD (which implies "false" for
- that shortcut). As a consequence,
- "<exclude-unlisted-classes> false
- </exclude-unlisted-classes/>" is not supported! Simply
- omit the "exclude-unlisted-classes" element if you would like entity
- class scanning to actually happen.
+ <bean id="myProductDao" class="product.ProductDaoImpl"/>
- This is the most powerful JPA setup option, allowing for
- flexible local configuration within the application. It supports links
- to an existing JDBC DataSource,
- supports both local and global transactions, etc. However, it also
- imposes requirements onto the runtime environment, such as the
- availability of a weaving-capable ClassLoader if the persistence
- provider demands byte-code transformation.
+</beans>
- Note that this option may conflict with the built-in JPA
- capabilities of a Java EE 5 server. So when running in a full Java EE
- 5 environment, consider obtaining your
- EntityManagerFactory from JNDI.
- Alternatively, specify a custom "persistenceXmlLocation" on your
- LocalContainerEntityManagerFactoryBean
- definition, e.g. "META-INF/my-persistence.xml", and only include a
- descriptor with that name in your application jar files. Since the
- Java EE 5 server will only look for default
- META-INF/persistence.xml files, it will ignore such
- custom persistence units and hence avoid conflicts with a
- Spring-driven JPA setup upfront. (This applies to Resin 3.1, for
- example.)
+ Note: As alternative to defining a
+ PersistenceAnnotationBeanPostProcessor
+ explicitly, consider using Spring 2.5's
+ context:annotation-config XML element in your
+ application context configuration. This will automatically register all
+ of Spring's standard post-processors for annotation-based configuration
+ (including CommonAnnotationBeanPostProcessor
+ etc).
- Use this option for full JPA capabilities in a
- Spring-based application environment. This includes web containers
- such as Tomcat as well as standalone applications and integration
- tests with sophisticated persistence requirements.
+ <beans>
-
- When is load-time weaving required?
+ <!-- post-processors for all standard config annotations -->
+ <context:annotation-config/>
- Not all JPA providers impose the need of a JVM agent
- (Hibernate being an example). If your provider does not require an
- agent or you have other alternatives (for example applying
- enhancements at build time through a custom compiler or an ant task)
- the load-time weaver should not be
- used.
-
+ <bean id="myProductDao" class="product.ProductDaoImpl"/>
- The LoadTimeWeaver interface is a
- Spring-provided class that allows JPA
- ClassTransformer instances to be
- plugged in a specific manner depending on the environment (web
- container/application server). Hooking
- ClassTransformers through a Java 5 agent
- is typically not efficient - the agents work against the
- entire virtual machine and inspect
- every class that is loaded - something that is
- typically undesirable in a production server enviroment.
+</beans>
- Spring provides a number of
- LoadTimeWeaver implementations for
- various environments, allowing
- ClassTransformer instances to be
- applied only per ClassLoader and not per
- VM.
+ The main issue with such a DAO is that it always creates a new
+ EntityManager via the factory. This can
+ be easily overcome by requesting a transactional
+ EntityManager (also called "shared
+ EntityManager", since it is a shared, thread-safe proxy for the actual
+ transactional EntityManager) to be injected instead of the
+ factory:
- The following sections will discuss typical JPA weaving setup on
- Tomcat as well as using Spring's VM agent. See the AOP chapter section
- entitled for details on how to
- set up general load-time weaving, covering Tomcat and the VM agent as
- well as WebLogic, OC4J, GlassFish and Resin.
+ public class ProductDaoImpl implements ProductDao {
-
- Tomcat load-time weaving setup (5.0+)
+ @PersistenceContext
+ private EntityManager em;
- Apache Tomcat's
- default ClassLoader does not support class transformation but allows
- custom ClassLoaders to be used. Spring offers the
- TomcatInstrumentableClassLoader (inside the
- org.springframework.instrument.classloading.tomcat
- package) which extends the Tomcat ClassLoader
- (WebappClassLoader) and allows JPA
- ClassTransformer instances to 'enhance' all
- classes loaded by it. In short, JPA transformers will be applied
- only inside a specific web application (which uses the
- TomcatInstrumentableClassLoader).
+ public Collection loadProductsByCategory(String category) {
+ Query query = em.createQuery("from Product as p where p.category = :category");
+ query.setParameter("category", category);
+ return query.getResultList();
+ }
+}
- In order to use the custom ClassLoader on:
+ Note that the @PersistenceContext annotation
+ has an optional attribute type, which defaults to
+ PersistenceContextType.TRANSACTION. This default is
+ what you need to receive a "shared EntityManager" proxy. The
+ alternative, PersistenceContextType.EXTENDED, is a
+ completely different affair: This results in a so-called "extended
+ EntityManager", which is not thread-safe and hence
+ must not be used in a concurrently accessed component such as a
+ Spring-managed singleton bean. Extended EntityManagers are only supposed
+ to be used in stateful components that, for example, reside in a
+ session, with the lifecycle of the EntityManager not tied to a current
+ transaction but rather being completely up to the application.
-
-
- Tomcat 5.0.x/5.5.x
-
+
+ Method and Field level Injection
-
-
- Copy spring-tomcat-weaver.jar into
- $CATALINA_HOME/server/lib (where
- $CATALINA_HOME represents the root of the
- Tomcat installation).
-
+ Annotations that indicate dependency injections (such as
+ @PersistenceUnit and
+ @PersistenceContext) can be applied on field or
+ methods inside a class, therefore the expression "method/field level
+ injection". Field-level annotations concise and easier to use while
+ method-level allow for processing the injected dependency. In both
+ cases the member visibility (public, protected, private) does not
+ matter.
-
- Instruct Tomcat to use the custom ClassLoader (instead
- of the default one) by editing the web application context
- file:
+ What about class level annotations?
- <Context path="/myWebApp" docBase="/my/webApp/location">
- <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
-</Context>
+ On the Java EE 5 platform, they are used for dependency
+ declaration and not for resource injection.
+
- Tomcat 5.0.x and 5.5.x series support several context
- locations: server configuration file
- ($CATALINA_HOME/conf/server.xml), the
- default context configuration
- ($CATALINA_HOME/conf/context.xml) that
- affects all deployed web applications and per-webapp
- configurations, deployed on the server
- ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml)
- side or along with the webapp
- (your-webapp.war/META-INF/context.xml).
- For efficiency, inside the web-app configuration style is
- recommended since only applications which use JPA will use the
- custom ClassLoader. See the Tomcat 5.x documentation
- for more details about available context locations.
+ The injected EntityManager is
+ Spring-managed (aware of the ongoing transaction). It is important to
+ note that even though the new implementation prefers method level
+ injection (of an EntityManager instead of
+ an EntityManagerFactory), no change is
+ required in the application context XML due to annotation usage.
- Note that versions prior to 5.5.20 contained a bug in
- the XML configuration parsing preventing usage of
- Loader tag inside
- server.xml (no matter if a ClassLoader is
- specified or not (be it the official or a custom one). See
- Tomcat's bugzilla for more
- details.
+ The main advantage of this DAO style is that it depends on Java
+ Persistence API; no import of any Spring class is required. Moreover, as
+ the JPA annotations are understood, the injections are applied
+ automatically by the Spring container. This is of course appealing from
+ a non-invasiveness perspective, and might feel more natural to JPA
+ developers.
+
- If you are using Tomcat 5.5.20+ you can set
- useSystemClassLoaderAsParent to
- false to fix the problem: <Context path="/myWebApp" docBase="/my/webApp/location">
- <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
- useSystemClassLoaderAsParent="false"/>
-</Context>
-
-
+
+ Exception Translation
-
- Tomcat 6.0.x
-
+ However, the DAO throws the plain
+ PersistenceException exception class (which is
+ unchecked, and so does not have to be declared or caught) but also
+ IllegalArgumentException and
+ IllegalStateException, which means that callers
+ can only treat exceptions as generally fatal - unless they want to
+ depend on JPA's own exception structure. Catching specific causes such
+ as an optimistic locking failure is not possible without tying the
+ caller to the implementation strategy. This tradeoff might be acceptable
+ to applications that are strongly JPA-based and/or do not need any
+ special exception treatment. However, Spring offers a solution allowing
+ exception translation to be applied transparently through the
+ @Repository annotation:
-
-
- Copy spring-tomcat-weaver.jar into
- $CATALINA_HOME/lib (where
- $CATALINA_HOME represents the root of the
- Tomcat installation).
-
+ @Repository
+public class ProductDaoImpl implements ProductDao {
-
- Instruct Tomcat to use the custom ClassLoader (instead
- of the default one) by editing the web application context
- file:
+ // class body here...
- <Context path="/myWebApp" docBase="/my/webApp/location">
- <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
-</Context>
+}
- Tomcat 6.0.x (similar to 5.0.x/5.5.x) series support
- several context locations: server configuration file
- ($CATALINA_HOME/conf/server.xml), the
- default context configuration
- ($CATALINA_HOME/conf/context.xml) that
- affects all deployed web applications and per-webapp
- configurations, deployed on the server
- ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml)
- side or along with the webapp
- (your-webapp.war/META-INF/context.xml).
- For efficiency, inside the web-app configuration style is
- recommended since only applications which use JPA will use the
- custom ClassLoader. See the Tomcat 5.x documentation
- for more details about available context locations.
-
-
-
+ <beans>
- The last step required on all Tomcat versions, is to use the
- appropriate the LoadTimeWeaver when
- configuring
- LocalContainerEntityManagerFactoryBean:
+ <!-- Exception translation bean post processor -->
+ <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
- <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- <property name="loadTimeWeaver">
- <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
- </property>
-</bean>
+ <bean id="myProductDao" class="product.ProductDaoImpl"/>
- Using this technique, JPA applications relying on
- instrumentation, can run in Tomcat without the need of an agent.
- This is important especially when hosting applications which rely on
- different JPA implementations since the JPA transformers are applied
- only at ClassLoader level and thus, are isolated from each
- other.
+</beans>
-
- If TopLink Essentials is being used a JPA provider under
- Tomcat, please place the toplink-essentials jar under
- $CATALINA_HOME/shared/lib folder instead of
- your war.
-
-
+ The postprocessor will automatically look for all exception
+ translators (implementations of the
+ PersistenceExceptionTranslator interface)
+ and advise all beans marked with the
+ @Repository annotation so that the
+ discovered translators can intercept and apply the appropriate
+ translation on the thrown exceptions.
+
+ In summary: DAOs can be implemented based on the plain Java
+ Persistence API and annotations, while still being able to benefit from
+ Spring-managed transactions, dependency injection, and transparent
+ exception conversion (if desired) to Spring's custom exception
+ hierarchies.
+
+
+
+
+ JpaDialect
-
- General load-time weaving using the VM agent
+ As an advanced feature JpaTemplate,
+ JpaTransactionManager and subclasses of
+ AbstractEntityManagerFactoryBean support a custom
+ JpaDialect, to be passed into the
+ "jpaDialect" bean property. In such a scenario, the DAOs won't receive an
+ EntityManagerFactory reference but rather a
+ full JpaTemplate instance instead (for example,
+ passed into JpaDaoSupport's "jpaTemplate"
+ property). A JpaDialect implementation can
+ enable some advanced features supported by Spring, usually in a
+ vendor-specific manner:
- For environments where class instrumentation is required but
- are not supported by the existing LoadTimeWeaver implementations, a
- JDK agent can be the only solution. For such cases, Spring provides
- InstrumentationLoadTimeWeaver which requires
- a Spring-specific (but very general) VM agent (spring-agent.jar):
+
+
+ applying specific transaction semantics (such as custom
+ isolation level or transaction timeout)
+
- <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- <property name="loadTimeWeaver">
- <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
- </property>
-</bean>
+
+ retrieving the transactional JDBC
+ Connection (for exposure to JDBC-based
+ DAOs)
+
- Note that the virtual machine has to be started with the
- Spring agent, by supplying the following JVM options:
+
+ advanced translation of PersistenceExceptions
+ to Spring DataAccessExceptions
+
+
- -javaagent:/path/to/spring-agent.jar
-
+ This is particularly valuable for special transaction semantics and
+ for advanced translation of exception. Note that the default
+ implementation used (DefaultJpaDialect) doesn't
+ provide any special capabilities and if the above features are required,
+ the appropriate dialect has to be specified.
-
- Context-wide load-time weaver setup
+ See the JpaDialect Javadoc for more
+ details of its operations and how they are used within Spring's JPA
+ support.
+
- Since Spring 2.5, a context-wide
- LoadTimeWeaver can be configured
- using the context:load-time-weaver configuration
- element. Such a 'global' weaver will be picked up by all JPA
- LocalContainerEntityManagerFactoryBeans
- automatically.
+
+ Transaction Management
- This is the preferred way of setting up a load-time weaver,
- delivering autodetection of the platform (WebLogic, OC4J, GlassFish,
- Tomcat, Resin, VM agent) as well as automatic propagation of the
- weaver to all weaver-aware beans.
+ To execute service operations within transactions, you can use
+ Spring's common declarative transaction facilities. For example:
- <context:load-time-weaver/>
+ <?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://www.springframework.org/schema/tx
+ http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
+ http://www.springframework.org/schema/aop
+ http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
-<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- ...
-</bean>
+ <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
+ <property name="entityManagerFactory" ref="myEmf"/>
+ </bean>
- See the section entitled
- for details on how to set up general load-time weaving, covering
- Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and
- Resin.
-
-
+ <bean id="myProductService" class="product.ProductServiceImpl">
+ <property name="productDao" ref="myProductDao"/>
+ </bean>
+
+ <aop:config>
+ <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/>
+ <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
+ </aop:config>
-
- Dealing with multiple persistence units
+ <tx:advice id="txAdvice" transaction-manager="myTxManager">
+ <tx:attributes>
+ <tx:method name="increasePrice*" propagation="REQUIRED"/>
+ <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
+ <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
+ </tx:attributes>
+ </tx:advice>
- For applications that rely on multiple persistence units
- locations (stored in various jars in the classpath for example),
- Spring offers the
- PersistenceUnitManager to act as a
- central repository and avoid the (potentially expensive) persistence
- units discovery process. The default implementation allows multiple
- locations to be specified (by default, the classpath is searched for
- 'META-INF/persistence.xml' files) which are
- parsed and later on retrieved through the persistence unit
- name:
+</beans>
- <bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
- <property name="persistenceXmlLocation">
- <list>
- <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
- <value>classpath:/my/package/**/custom-persistence.xml</value>
- <value>classpath*:META-INF/persistence.xml</value>
- </list>
- </property>
- <property name="dataSources">
- <map>
- <entry key="localDataSource" value-ref="local-db"/>
- <entry key="remoteDataSource" value-ref="remote-db"/>
- </map>
- </property>
- <!-- if no datasource is specified, use this one -->
- <property name="defaultDataSource" ref="remoteDataSource"/>
-</bean>
+ Spring JPA allows a configured
+ JpaTransactionManager to expose a JPA transaction
+ to JDBC access code that accesses the same JDBC
+ DataSource, provided that the registered
+ JpaDialect supports retrieval of the
+ underlying JDBC Connection. Out of the box,
+ Spring provides dialects for the Toplink, Hibernate and OpenJPA JPA
+ implementations. See the next section for details on the
+ JpaDialect mechanism.
+
-<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- <property name="persistenceUnitManager" ref="pum"/>
-</bean>
+
+ JDO
- Note that the default implementation allows customization of the
- persistence unit infos before feeding them to the JPA provider
- declaratively through its properties (which affect
- all hosted units) or programmatically, through
- the PersistenceUnitPostProcessor (which
- allows persistence unit selection). If no
- PersistenceUnitManager is specified,
- one will be created and used internally by
- LocalContainerEntityManagerFactoryBean.
-
-
+ Spring supports the standard JDO 2.0/2.1 API as data access
+ strategy, following the same style as the Hibernate support. The
+ corresponding integration classes reside in the
+ org.springframework.orm.jdo package.
-
- JpaTemplate and
- JpaDaoSupport
+
+ PersistenceManagerFactory
+ setup
- Each JPA-based DAO will then receive a
- EntityManagerFactory via dependency
- injection. Such a DAO can be coded against plain JPA and work with the
- given EntityManagerFactory or through
- Spring's JpaTemplate:
+ Spring provides a
+ LocalPersistenceManagerFactoryBean class that
+ allows for defining a local JDO
+ PersistenceManagerFactory within a Spring
+ application context:
<beans>
- <bean id="myProductDao" class="product.ProductDaoImpl">
- <property name="entityManagerFactory" ref="myEmf"/>
+ <bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
+ <property name="configLocation" value="classpath:kodo.properties"/>
</bean>
</beans>
- public class JpaProductDao implements ProductDao {
-
- private JpaTemplate jpaTemplate;
+ Alternatively, a
+ PersistenceManagerFactory can also be set
+ up through direct instantiation of a
+ PersistenceManagerFactory implementation
+ class. A JDO PersistenceManagerFactory
+ implementation class is supposed to follow the JavaBeans pattern, just
+ like a JDBC DataSource implementation
+ class, which is a natural fit for a Spring bean definition. This setup
+ style usually supports a Spring-defined JDBC
+ DataSource, passed into the
+ "connectionFactory" property. For example, for the open source JDO
+ implementation JPOX ():
- public void setEntityManagerFactory(EntityManagerFactory emf) {
- this.jpaTemplate = new JpaTemplate(emf);
- }
+ <beans>
- public Collection loadProductsByCategory(final String category) throws DataAccessException {
- return (Collection) this.jpaTemplate.execute(new JpaCallback() {
- public Object doInJpa(EntityManager em) throws PersistenceException {
- Query query = em.createQuery("from Product as p where p.category = :category");
- query.setParameter("category", category);
- List result = query.getResultList();
- // do some further processing with the result list
- return result;
- }
- });
- }
-}
+ <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
+ <property name="driverClassName" value="${jdbc.driverClassName}"/>
+ <property name="url" value="${jdbc.url}"/>
+ <property name="username" value="${jdbc.username}"/>
+ <property name="password" value="${jdbc.password}"/>
+ </bean>
- The JpaCallback implementation
- allows any type of JPA data access. The
- JpaTemplate will ensure that
- EntityManagers are properly opened and
- closed and automatically participate in transactions. Moreover, the
- JpaTemplate properly handles exceptions, making
- sure resources are cleaned up and the appropriate transactions rolled
- back. The template instances are thread-safe and reusable and they can
- be kept as instance variable of the enclosing class. Note that
- JpaTemplate offers single-step actions such as
- find, load, merge, etc along with alternative convenience methods that
- can replace one line callback implementations.
-
- Furthermore, Spring provides a convenient
- JpaDaoSupport base class that provides the
- get/setEntityManagerFactory and
- getJpaTemplate() to be used by
- subclasses:
-
- public class ProductDaoImpl extends JpaDaoSupport implements ProductDao {
-
- public Collection loadProductsByCategory(String category) throws DataAccessException {
- Map<String, String> params = new HashMap<String, String>();
- params.put("category", category);
- return getJpaTemplate().findByNamedParams("from Product as p where p.category = :category", params);
- }
-}
+ <bean id="myPmf" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close">
+ <property name="connectionFactory" ref="dataSource"/>
+ <property name="nontransactionalRead" value="true"/>
+ </bean>
- Besides working with Spring's JpaTemplate,
- one can also code Spring-based DAOs against the JPA, doing one's own
- explicit EntityManager handling. As also
- elaborated in the corresponding Hibernate section, the main advantage of
- this approach is that your data access code is able to throw checked
- exceptions. JpaDaoSupport offers a variety of
- support methods for this scenario, for retrieving and releasing a
- transaction EntityManager, as well as for
- converting exceptions.
-
- JpaTemplate mainly exists as a sibling of JdoTemplate
- and HibernateTemplate, offering the same style for people used to it.
- For newly started projects, consider adopting the native JPA style of
- coding data access objects instead, based on a "shared EntityManager"
- reference obtained through the JPA
- @PersistenceContext annotation (using Spring's
- PersistenceAnnotationBeanPostProcessor; see below
- for details.)
-
+</beans>
-
- Implementing DAOs based on plain JPA
+ A JDO PersistenceManagerFactory can
+ also be set up in the JNDI environment of a J2EE application server,
+ usually through the JCA connector provided by the particular JDO
+ implementation. Spring's standard
+ JndiObjectFactoryBean can be used to retrieve and
+ expose such a PersistenceManagerFactory.
+ However, outside an EJB context, there is often no compelling benefit in
+ holding the PersistenceManagerFactory in
+ JNDI: only choose such setup for a good reason. See "container resources
+ versus local resources" in the Hibernate section for a discussion; the
+ arguments there apply to JDO as well.
+
-
- While EntityManagerFactory
- instances are thread-safe,
- EntityManager instances are not. The
- injected JPA EntityManager behave just
- like an EntityManager fetched from an
- application server's JNDI environment, as defined by the JPA
- specification. It will delegate all calls to the current transactional
- EntityManager, if any; else, it will
- fall back to a newly created
- EntityManager per operation, making it
- thread-safe.
-
+
+ Implementing DAOs based on the plain JDO API
- It is possible to write code against the plain JPA without using
- any Spring dependencies, using an injected
- EntityManagerFactory or
- EntityManager. Note that Spring can
- understand @PersistenceUnit and
- @PersistenceContext annotations both at
- field and method level if a
- PersistenceAnnotationBeanPostProcessor is
- enabled. A corresponding DAO implementation might look like this:
+ DAOs can also be written against plain JDO API, without any Spring
+ dependencies, directly using an injected
+ PersistenceManagerFactory. A
+ corresponding DAO implementation looks like as follows:
public class ProductDaoImpl implements ProductDao {
- private EntityManagerFactory emf;
+ private PersistenceManagerFactory persistenceManagerFactory;
- @PersistenceUnit
- public void setEntityManagerFactory(EntityManagerFactory emf) {
- this.emf = emf;
+ public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
+ this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
- EntityManager em = this.emf.createEntityManager();
+ PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
try {
- Query query = em.createQuery("from Product as p where p.category = ?1");
- query.setParameter(1, category);
- return query.getResultList();
+ Query query = pm.newQuery(Product.class, "category = pCategory");
+ query.declareParameters("String pCategory");
+ return query.execute(category);
}
finally {
- if (em != null) {
- em.close();
- }
+ pm.close();
}
}
}
- The DAO above has no dependency on Spring and still fits nicely
- into a Spring application context, just like it would if coded against
- Spring's JpaTemplate. Moreover, the DAO takes
- advantage of annotations to require the injection of the default
- EntityManagerFactory:
+ As the above DAO still follows the Dependency Injection pattern,
+ it still fits nicely into a Spring container, just like it would if
+ coded against Spring's JdoTemplate:
<beans>
- <!-- bean post-processor for JPA annotations -->
- <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
-
- <bean id="myProductDao" class="product.ProductDaoImpl"/>
+ <bean id="myProductDao" class="product.ProductDaoImpl">
+ <property name="persistenceManagerFactory" ref="myPmf"/>
+ </bean>
</beans>
- Note: As alternative to defining a
- PersistenceAnnotationBeanPostProcessor
- explicitly, consider using Spring 2.5's
- context:annotation-config XML element in your
- application context configuration. This will automatically register all
- of Spring's standard post-processors for annotation-based configuration
- (including CommonAnnotationBeanPostProcessor
- etc).
+ The main issue with such DAOs is that they always get a new
+ PersistenceManager from the factory. To
+ still access a Spring-managed transactional
+ PersistenceManager, consider defining a
+ TransactionAwarePersistenceManagerFactoryProxy
+ (as included in Spring) in front of your target
+ PersistenceManagerFactory, passing the
+ proxy into your DAOs.
<beans>
- <!-- post-processors for all standard config annotations -->
- <context:annotation-config/>
+ <bean id="myPmfProxy"
+ class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
+ <property name="targetPersistenceManagerFactory" ref="myPmf"/>
+ </bean>
- <bean id="myProductDao" class="product.ProductDaoImpl"/>
+ <bean id="myProductDao" class="product.ProductDaoImpl">
+ <property name="persistenceManagerFactory" ref="myPmfProxy"/>
+ </bean>
</beans>
- The main issue with such a DAO is that it always creates a new
- EntityManager via the factory. This can
- be easily overcome by requesting a transactional
- EntityManager (also called "shared
- EntityManager", since it is a shared, thread-safe proxy for the actual
- transactional EntityManager) to be injected instead of the
- factory:
+ Your data access code will then receive a transactional
+ PersistenceManager (if any) from the
+ PersistenceManagerFactory.getPersistenceManager()
+ method that it calls. The latter method call goes through the proxy,
+ which will first check for a current transactional
+ PersistenceManager before getting a new
+ one from the factory. close() calls on the
+ PersistenceManager will be ignored in
+ case of a transactional
+ PersistenceManager.
+
+ If your data access code will always run within an active
+ transaction (or at least within active transaction synchronization), it
+ is safe to omit the PersistenceManager.close()
+ call and thus the entire finally block, which you
+ might prefer to keep your DAO implementations concise:
public class ProductDaoImpl implements ProductDao {
- @PersistenceContext
- private EntityManager em;
+ private PersistenceManagerFactory persistenceManagerFactory;
+
+ public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
+ this.persistenceManagerFactory = pmf;
+ }
public Collection loadProductsByCategory(String category) {
- Query query = em.createQuery("from Product as p where p.category = :category");
- query.setParameter("category", category);
- return query.getResultList();
+ PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
+ Query query = pm.newQuery(Product.class, "category = pCategory");
+ query.declareParameters("String pCategory");
+ return query.execute(category);
}
}
- Note that the @PersistenceContext annotation
- has an optional attribute type, which defaults to
- PersistenceContextType.TRANSACTION. This default is
- what you need to receive a "shared EntityManager" proxy. The
- alternative, PersistenceContextType.EXTENDED, is a
- completely different affair: This results in a so-called "extended
- EntityManager", which is not thread-safe and hence
- must not be used in a concurrently accessed component such as a
- Spring-managed singleton bean. Extended EntityManagers are only supposed
- to be used in stateful components that, for example, reside in a
- session, with the lifecycle of the EntityManager not tied to a current
- transaction but rather being completely up to the application.
+ With such DAOs that rely on active transactions, it is recommended
+ to enforce active transactions through turning
+ TransactionAwarePersistenceManagerFactoryProxy's
+ "allowCreate" flag off:
-
- Method and Field level Injection
+ <beans>
+
+ <bean id="myPmfProxy"
+ class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
+ <property name="targetPersistenceManagerFactory" ref="myPmf"/>
+ <property name="allowCreate" value="false"/>
+ </bean>
+
+ <bean id="myProductDao" class="product.ProductDaoImpl">
+ <property name="persistenceManagerFactory" ref="myPmfProxy"/>
+ </bean>
+
+</beans>
+
+ The main advantage of this DAO style is that it depends on JDO API
+ only; no import of any Spring class is required. This is of course
+ appealing from a non-invasiveness perspective, and might feel more
+ natural to JDO developers.
+
+ However, the DAO throws plain
+ JDOException (which is unchecked, so does
+ not have to be declared or caught), which means that callers can only
+ treat exceptions as generally fatal - unless they want to depend on
+ JDO's own exception structure. Catching specific causes such as an
+ optimistic locking failure is not possible without tying the caller to
+ the implementation strategy. This tradeoff might be acceptable to
+ applications that are strongly JDO-based and/or do not need any special
+ exception treatment.
+
+ In summary: DAOs can be implemented based on plain JDO API, while
+ still being able to participate in Spring-managed transactions. This
+ might in particular appeal to people already familiar with JDO, feeling
+ more natural to them. However, such DAOs will throw plain
+ JDOException; conversion to Spring's
+ DataAccessException would have to happen
+ explicitly (if desired).
+
+
+
+ Transaction management
+
+ To execute service operations within transactions, you can use
+ Spring's common declarative transaction facilities. For example:
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<beans
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://www.springframework.org/schema/tx
+ http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
+ http://www.springframework.org/schema/aop
+ http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
+
+ <bean id="myTxManager" class="org.springframework.orm.jdo.JdoTransactionManager">
+ <property name="persistenceManagerFactory" ref="myPmf"/>
+ </bean>
+
+ <bean id="myProductService" class="product.ProductServiceImpl">
+ <property name="productDao" ref="myProductDao"/>
+ </bean>
+
+ <tx:advice id="txAdvice" transaction-manager="txManager">
+ <tx:attributes>
+ <tx:method name="increasePrice*" propagation="REQUIRED"/>
+ <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
+ <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
+ </tx:attributes>
+ </tx:advice>
+
+ <aop:config>
+ <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/>
+ <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
+ </aop:config>
+
+</beans>
+
+ Note that JDO requires an active transaction when modifying a
+ persistent object. There is no concept like a non-transactional flush in
+ JDO, in contrast to Hibernate. For this reason, the chosen JDO
+ implementation needs to be set up for a specific environment: in
+ particular, it needs to be explicitly set up for JTA synchronization, to
+ detect an active JTA transaction itself. This is not necessary for local
+ transactions as performed by Spring's
+ JdoTransactionManager, but it is necessary for
+ participating in JTA transactions (whether driven by Spring's
+ JtaTransactionManager or by EJB CMT / plain
+ JTA).
+
+ JdoTransactionManager is capable of
+ exposing a JDO transaction to JDBC access code that accesses the same
+ JDBC DataSource, provided that the
+ registered JdoDialect supports retrieval of the
+ underlying JDBC Connection. This is the
+ case for JDBC-based JDO 2.0 implementations by default.
+
+
+
+ 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
+
+
- Annotations that indicate dependency injections (such as
- @PersistenceUnit and
- @PersistenceContext) can be applied on field or
- methods inside a class, therefore the expression "method/field level
- injection". Field-level annotations concise and easier to use while
- method-level allow for processing the injected dependency. In both
- cases the member visibility (public, protected, private) does not
- matter.
+ See the JdoDialect Javadoc for more details
+ on its operations and how they are used within Spring's JDO
+ support.
+
+
- What about class level annotations?
+
+ iBATIS SQL Maps
- On the Java EE 5 platform, they are used for dependency
- declaration and not for resource injection.
-
+ The iBATIS support in the Spring Framework much resembles the JDBC /
+ Hibernate support in that it supports the same template style programming
+ and just as with JDBC or Hibernate, the iBATIS support works with Spring's
+ exception hierarchy and let's you enjoy the all IoC features Spring
+ has.
- The injected EntityManager is
- Spring-managed (aware of the ongoing transaction). It is important to
- note that even though the new implementation prefers method level
- injection (of an EntityManager instead of
- an EntityManagerFactory), no change is
- required in the application context XML due to annotation usage.
+ Transaction management can be handled through Spring's standard
+ facilities. There are no special transaction strategies for iBATIS, as
+ there is no special transactional resource involved other than a JDBC
+ Connection. Hence, Spring's standard JDBC
+ DataSourceTransactionManager or
+ JtaTransactionManager are perfectly
+ sufficient.
- The main advantage of this DAO style is that it depends on Java
- Persistence API; no import of any Spring class is required. Moreover, as
- the JPA annotations are understood, the injections are applied
- automatically by the Spring container. This is of course appealing from
- a non-invasiveness perspective, and might feel more natural to JPA
- developers.
-
+
+ Spring does actually support both iBatis 1.x and 2.x. However,
+ only support for iBatis 2.x is actually shipped with the core Spring
+ distribution. The iBatis 1.x support classes were moved to the Spring
+ Modules project as of Spring 2.0, and you are directed there for
+ documentation.
+
-
- Exception Translation
+
+ Setting up the SqlMapClient
- However, the DAO throws the plain
- PersistenceException exception class (which is
- unchecked, and so does not have to be declared or caught) but also
- IllegalArgumentException and
- IllegalStateException, which means that callers
- can only treat exceptions as generally fatal - unless they want to
- depend on JPA's own exception structure. Catching specific causes such
- as an optimistic locking failure is not possible without tying the
- caller to the implementation strategy. This tradeoff might be acceptable
- to applications that are strongly JPA-based and/or do not need any
- special exception treatment. However, Spring offers a solution allowing
- exception translation to be applied transparently through the
- @Repository annotation:
+ If we want to map the previous Account class with iBATIS 2.x we
+ need to create the following SQL map
+ 'Account.xml':
- @Repository
-public class ProductDaoImpl implements ProductDao {
+ <sqlMap namespace="Account">
- // class body here...
+ <resultMap id="result" class="examples.Account">
+ <result property="name" column="NAME" columnIndex="1"/>
+ <result property="email" column="EMAIL" columnIndex="2"/>
+ </resultMap>
-}
+ <select id="getAccountByEmail" resultMap="result">
+ select ACCOUNT.NAME, ACCOUNT.EMAIL
+ from ACCOUNT
+ where ACCOUNT.EMAIL = #value#
+ </select>
- <beans>
+ <insert id="insertAccount">
+ insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
+ </insert>
- <!-- Exception translation bean post processor -->
- <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
+</sqlMap>
- <bean id="myProductDao" class="product.ProductDaoImpl"/>
+ The configuration file for iBATIS 2 looks like this:
-</beans>
+ <sqlMapConfig>
- The postprocessor will automatically look for all exception
- translators (implementations of the
- PersistenceExceptionTranslator interface)
- and advise all beans marked with the
- @Repository annotation so that the
- discovered translators can intercept and apply the appropriate
- translation on the thrown exceptions.
+ <sqlMap resource="example/Account.xml"/>
- In summary: DAOs can be implemented based on the plain Java
- Persistence API and annotations, while still being able to benefit from
- Spring-managed transactions, dependency injection, and transparent
- exception conversion (if desired) to Spring's custom exception
- hierarchies.
-
-
+</sqlMapConfig>
-
- Transaction Management
+ Remember that iBATIS loads resources from the class path, so be
+ sure to add the 'Account.xml' file to the class
+ path.
- To execute service operations within transactions, you can use
- Spring's common declarative transaction facilities. For example:
+ We can use the SqlMapClientFactoryBean in
+ the Spring container. Note that with iBATIS SQL Maps 2.x, the JDBC
+ DataSource is usually specified on the
+ SqlMapClientFactoryBean, which enables lazy
+ loading.
- <?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
+ <beans>
- <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
- <property name="entityManagerFactory" ref="myEmf"/>
+ <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
+ <property name="driverClassName" value="${jdbc.driverClassName}"/>
+ <property name="url" value="${jdbc.url}"/>
+ <property name="username" value="${jdbc.username}"/>
+ <property name="password" value="${jdbc.password}"/>
</bean>
- <bean id="myProductService" class="product.ProductServiceImpl">
- <property name="productDao" ref="myProductDao"/>
+ <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
+ <property name="configLocation" value="WEB-INF/sqlmap-config.xml"/>
+ <property name="dataSource" ref="dataSource"/>
</bean>
-
- <aop:config>
- <aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/>
- <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
- </aop:config>
-
- <tx:advice id="txAdvice" transaction-manager="myTxManager">
- <tx:attributes>
- <tx:method name="increasePrice*" propagation="REQUIRED"/>
- <tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
- <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
- </tx:attributes>
- </tx:advice>
</beans>
+
- Spring JPA allows a configured
- JpaTransactionManager to expose a JPA transaction
- to JDBC access code that accesses the same JDBC
- DataSource, provided that the registered
- JpaDialect supports retrieval of the
- underlying JDBC Connection. Out of the box,
- Spring provides dialects for the Toplink, Hibernate and OpenJPA JPA
- implementations. See the next section for details on the
- JpaDialect mechanism.
-
+
+ Implementing DAOs based on plain iBATIS API
-
- JpaDialect
+ DAOs can also be written against plain iBATIS API, without any
+ Spring dependencies, directly using an injected
+ SqlMapClient. A corresponding DAO implementation
+ looks like as follows:
- As an advanced feature JpaTemplate,
- JpaTransactionManager and subclasses of
- AbstractEntityManagerFactoryBean support a custom
- JpaDialect, to be passed into the
- "jpaDialect" bean property. In such a scenario, the DAOs won't receive an
- EntityManagerFactory reference but rather a
- full JpaTemplate instance instead (for example,
- passed into JpaDaoSupport's "jpaTemplate"
- property). A JpaDialect implementation can
- enable some advanced features supported by Spring, usually in a
- vendor-specific manner:
+ public class SqlMapAccountDao implements AccountDao {
+
+ private SqlMapClient sqlMapClient;
+
+ public void setSqlMapClient(SqlMapClient sqlMapClient) {
+ this.sqlMapClient = sqlMapClient;
+ }
-
-
- applying specific transaction semantics (such as custom
- isolation level or transaction timeout)
-
+ public Account getAccount(String email) {
+ try {
+ return (Account) this.sqlMapClient.queryForObject("getAccountByEmail", email);
+ }
+ catch (SQLException ex) {
+ throw new MyDaoException(ex);
+ }
+ }
-
- retrieving the transactional JDBC
- Connection (for exposure to JDBC-based
- DAOs)
-
+ public void insertAccount(Account account) throws DataAccessException {
+ try {
+ this.sqlMapClient.update("insertAccount", account);
+ }
+ catch (SQLException ex) {
+ throw new MyDaoException(ex);
+ }
+ }
+}
-
- advanced translation of PersistenceExceptions
- to Spring DataAccessExceptions
-
-
+ In such a scenario, the SQLException thrown by
+ the iBATIS API needs to be handled in a custom fashion: usually,
+ wrapping it in your own application-specific DAO exception. Wiring in
+ the application context would still look like before, due to the fact
+ that the plain iBATIS-based DAO still follows the Dependency Injection
+ pattern:
- This is particularly valuable for special transaction semantics and
- for advanced translation of exception. Note that the default
- implementation used (DefaultJpaDialect) doesn't
- provide any special capabilities and if the above features are required,
- the appropriate dialect has to be specified.
+ <beans>
- See the JpaDialect Javadoc for more
- details of its operations and how they are used within Spring's JPA
- support.
+ <bean id="accountDao" class="example.SqlMapAccountDao">
+ <property name="sqlMapClient" ref="sqlMapClient"/>
+ </bean>
+
+</beans>
+
diff --git a/spring-framework-reference/src/spring-framework-reference.xml b/spring-framework-reference/src/spring-framework-reference.xml
index f9c3e49ea7e..9b18161341a 100644
--- a/spring-framework-reference/src/spring-framework-reference.xml
+++ b/spring-framework-reference/src/spring-framework-reference.xml
@@ -330,6 +330,7 @@
+