Platinum Partner
java,sql,frameworks,hibernate,persistence,spring framework,dao

Integrating Hibernate with Spring

In this article, we will look at  how Spring affects the application's data-access layer. Our discussion starts with the Data Access Object (DAO) pattern. This pattern, which is popular in the Java world, allows for a more manageable, more maintainable data-access tier. Then, we'll discuss how Spring affects application DAO classes when integrated with Hibernate.

Spring is a general-purpose framework that plays different roles in many areas of application architecture. One of these areas is persistence. Spring does not provide its own persistence framework. Instead, it provides an abstraction layer over JDBC, and a variety of O/R mapping frameworks, such as iBATIS SQL Maps, Hibernate, JDO, Apache OJB, and Oracle TopLink. This abstraction allows consistent, manageable data-access implementation. 

Spring's abstraction layer abstracts the application from the connection factory, the transaction API, and the exception hierarchies used by the underlying persistence technology. Application code always uses the Spring API to work with connection factories, utilizes Spring strategies for transaction management, and involves Spring's generic exception hierarchy to handle underlying exceptions. Spring sits between the application classes and the O/R mapping tool, undertakes transactions, and manages connection objects. It translates the underlying persistence exceptions thrown by Hibernate to meaningful, unchecked exceptions of type DataAccessException. Moreover, Spring provides IoC and AOP, which can be used in the persistence layer. Spring undertakes Hibernate's transactions and provides a more powerful, comprehensive approach to transaction management.

 

The Data Access Object pattern

Although you can obtain a Session object and connect to Hibernate anywhere in the application, it's recommended that all interactions with Hibernate be done only through distinct classes. Regarding this, there is a JEE design pattern, called the DAO pattern. According to the DAO pattern, all persistent operations should be performed via specific classes, technically called DAO classes. These classes are used exclusively for communicating with the data tier. The purpose of this pattern is to separate persistence-related code from the application's business logic, which makes for more manageable and maintainable code, letting you change the persistence strategy flexibly, without changing the business rules or workflow logic.

The DAO pattern states that we should define a DAO interface corresponding to each DAO class. This DAO interface outlines the structure of a DAO class, defines all of the persistence operations that the business layer needs, and (in Spring-based applications) allows us to apply IoC to decouple the business layer from the DAO class.

 

Service Facade Pattern

In implementation of data access tier, the Service Facade Pattern is always used in addition to the DAO pattern. This pattern indicates using an intermediate object, called service object, between all business tier objects and DAO objects. The service object assembles the DAO methods to be managed as a unit of work. Note that only one service class is created for all DAOs that are implemented in each use case.

The service class uses instances of DAO interfaces to interact with them. These instances are instantiated from the concrete DAO classes by the IoC container at runtime. Therefore, the service object is unaware of the actual DAO implementation details.

Regardless of the persistence strategy your application uses (even if it uses direct JDBC), applying the DAO and Service Facade patterns to decouple application tiers is highly recommended.


Data tier implementation with Hibernate

Let's now see how the discussed patterns are applied to the application that directly uses Hibernate. The following code shows a sample DAO interface:

package com.packtpub.springhibernate.ch13;import java.util.Collection;public interface StudentDao {  public Student getStudent(long id);  public Collection getAllStudents();  public Collection getGraduatedStudents();  public Collection findStudents(String lastName);  public void saveStudent(Student std);  public void removeStudent(Student std);}

The following code shows a DAO class that implements this DAO interface:

package com.packtpub.springhibernate.ch13;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.HibernateException;import org.hibernate.Query;import java.util.Collection;public class HibernateStudentDao implements StudentDao {  SessionFactory sessionFactory;  public Student getStudent(long id) {    Student student = null;    Session session = HibernateHelper.getSession();    Transaction tx = null;    try {      tx = session.beginTransaction();      student = (Student) session.get(Student.class, new Long(id));      tx.commit();      tx = null;    } catch (HibernateException e) {      if (tx != null)        tx.rollback();      throw e;    } finally {      session.close();    }    return student;  }  public Collection getAllStudents(){    Collection allStudents = null;    Session session = HibernateHelper.getSession();    Transaction tx = null;    try {      tx = session.beginTransaction();      Query query = session.createQuery(                  "from Student std order by std.lastName, std.firstName");      allStudents = query.list();      tx.commit();      tx = null;    } catch (HibernateException e) {      if (tx != null)        tx.rollback();      throw e;    } finally {      session.close();    }    return allStudents;  }  public Collection getGraduatedStudents(){    Collection graduatedStudents = null;    Session session = HibernateHelper.getSession();    Transaction tx = null;    try {      tx = session.beginTransaction();      Query query = session.createQuery(                        "from Student std where std.status=1");      graduatedStudents = query.list();      tx.commit();      tx = null;    } catch (HibernateException e) {      if (tx != null)        tx.rollback();      throw e;    } finally {      session.close();    }    return graduatedStudents;  }  public Collection findStudents(String lastName) {    Collection students = null;    Session session = HibernateHelper.getSession();    Transaction tx = null;    try {      tx = session.beginTransaction();      Query query = session.createQuery(                  "from Student std where std.lastName like ?");      query.setString(1, lastName + "%");      students = query.list();      tx.commit();      tx = null;    } catch (HibernateException e) {      if (tx != null)        tx.rollback();      throw e;    } finally {      session.close();    }    return students;  }  public void saveStudent(Student std) {    Session session = HibernateHelper.getSession();    Transaction tx = null;    try {      tx = session.beginTransaction();      session.saveOrUpdate(std);      tx.commit();      tx = null;    } catch (HibernateException e) {      if (tx != null)        tx.rollback();      throw e;    } finally {      session.close();    }  }  public void removeStudent(Student std) {    Session session = HibernateHelper.getSession();    Transaction tx = null;    try {      tx = session.beginTransaction();      session.delete(std);      tx.commit();      tx = null;    } catch (HibernateException e) {      if (tx != null)        tx.rollback();      throw e;    } finally {      session.close();    }  }  public void setSessionFactory(SessionFactory sessionFactory) {    this.sessionFactory = sessionFactory;  }}

 

As you can see, all implemented methods do routines. All obtain a Session object at first, get a Transaction object, perform a persistence operation, commit the transaction, rollback the transaction if exception occurs, and finally close the Session object. Each method contains much boilerplate code that is very similar to the other methods.

Although applying the DAO pattern to the persistence code leads to more manageable and maintainable code, the DAO classes still include much boilerplate code. Each DAO method must obtain a Session instance, start a transaction, perform the persistence operation, and commit the transaction. Additionally, each DAO method should include its own duplicated exception-handling implementation. These are exactly the problems that motivate us to use Spring with Hibernate.

Template Pattern: To clean the code and provide more manageable code, Spring utilizes a pattern called Template Pattern. By this pattern, a template object wraps all of the boilerplate repetitive code. Then, this object delegates the persistence calls as a part of functionality in the template. In the Hibernate case, HibernateTemplate extracts all of the boilerplate code, such as obtaining a Session, performing transaction, and handing exceptions.



Data tier implementation with Spring

With Spring, you do not need to implement code for obtaining Session objects, starting and committing transactions, and handling Hibernate exceptions. Instead, you use a HibernateTemplate instance to delegate persistence calls to Hibernate, without direct interaction with Hibernate.

Here are some benefits of using Spring in the persistence layer, instead of using direct interaction with Hibernate:

  • With Spring, the HibernateTemplate object interacts with Hibernate. This object removes the boilerplate code from DAO implementations.
  • Any invocation of one of HibernateTemplate's methods throws the generic DataAccessException exception instead of HibernateException (a Hibernate-specific exception).
  • Spring lets us demarcate transactions declaratively, instead of implementing duplicated transaction-management code.

The HibernateTemplate class uses a SessionFactory instance internally to obtain Session objects for Hibernate interaction. Interestingly, you can configure the SessionFactory object via the Spring IoC container to be instantiated and injected into DAO objects.

The next sections discuss how HibernateTemplate is used in DAO classes, and how it is configured with SessionFactory in the Spring IoC container. First, let's look at the Spring exception hierarchy.

 

Spring exception translation

Spring provides its own exception hierarchy, which sits on the exception hierarchies of the O/R mapping tools it supports. It catches any database exception or error that might be thrown through JDBC, or the underlying O/R mapping tool, and translates the caught exception to a corresponding exception in its own hierarchy. The Spring exception hierarchy is defined as a subclass of org.springframework.dao.DataAccessException. Spring catches any exception thrown in the underlying persistence technology and wraps it in a DataAccessException instance. The DataAccessException object is an unchecked exception, because it extends RuntimeException and you do not need to catch it if you do not want to.

 

Refactoring DAO classes to use Spring

Spring provides distinct DAO base classes for the different data-access technologies it supports. For instance, Spring provides HibernateDaoSupport for Hibernate, SqlMapClientDaoSupport for iBATIS SQL Maps, and JdoDaoSupport for JDO. These classes wrap the common properties and methods that are required in all DAO implementation subclasses.

When you use Hibernate with Spring, the DAO classes extend the Spring org.springframework.orm.hibernate3.support.HibernateDaoSupport class. This class wraps an instance of org.springframework.orm.hibernate3.HibernateTemplate, which in turn wraps an org.hibernate.SessionFactory instance. As you will soon see in this article, extending the HibernateDaoSupport class lets you configure all DAO implementations consistently as beans inside the Spring IoC container. Their SessionFactory property is configured and set up via the Spring context.

The following code shows a simple DAO interface for a Spring-based DAO implementation:

package com.packtpub.springhibernate.ch13;import java.util.Collection;public interface StudentDao {  public Student getStudent(long id);  public Collection getAllStudents();  public Collection getGraduatedStudents();  public Collection findStudents(String lastName);  public void saveStudent(Student std);  public void removeStudent(Student std);}

 

Here, StudentDao is the DAO interface, with the same structure as the interface shown in the following code.

HibernateException is thrown for any failure when directly interacting with Hibernate. When Spring is used, HibernateException is caught by Spring and translated to DataAccessException for any persistence failure. Both exceptions are unchecked, so you do not need to catch them if you don't want to do.

 

The following code shows the DAO implementation for this DAO interface, which now uses Spring to interact with Hibernate:

package com.packtpub.springhibernate.ch13;import org.springframework.orm.hibernate3.support.HibernateDaoSupport;import java.util.Collection;public class HibernateStudentDao extends HibernateDaoSupport implements StudentDao {  public Student getStudent(long id) {    return (Student) getHibernateTemplate().get(Student.class, new Long(id));  }  public Collection getAllStudents(){    return getHibernateTemplate().      find("from Student std order by std.lastName, std.firstName");  }  public Collection getGraduatedStudents(){    return getHibernateTemplate().find("from Student std where std.status=1");  }  public Collection findStudents(String lastName) {    return getHibernateTemplate().      find("from Student std where std.lastName like ?", lastName + "%");  }  public void saveStudent(Student std) {    getHibernateTemplate().saveOrUpdate(std);  }  public void removeStudent(Student std) {    getHibernateTemplate().delete(std);  }}

 

As you can see, all of the persistent methods in the DAO class use the getHibernateTemplate() method to access the HibernateTemplate object. As you saw in the previous section, HibernateTemplate is a Spring convenience class that delegates DAO calls to the Hibernate Session API. This class exposes all of Hibernate's Session methods, as well as a variety of other convenient methods that DAO classes may need. Because HibernateTemplate convenient methods are not exposed by the Session interface, you can use find() and findByCriteria() when you want to execute HQL or create a Criteria object. Additionally, it wraps all of the underlying exceptions thrown by the Session method with instances of the unchecked org.springframework.dao.DataAccessException.

For convenience, I recommend using the HibernateDaoSupport class as the base class for all Hibernate DAO implementations, but you can ignore this class and work directly with a HibernateTemplate instance in DAO classes. To do so, define a property of HibernateTemplate in the DAO class, which is initialized and set up via the Spring IoC container.

The following code shows the DAO class, which now uses HibernateTemplate directly. Note that this approach is not recommended because it gets you involved with the HibernateTemplate object in both the DAO class and the DAO configuration in the Spring context:

package com.packtpub.springhibernate.ch13;import org.springframework.orm.hibernate3.HibernateTemplate;import java.util.Collection;public class HibernateStudentDao implements StudentDao {      HibernateTemplate hibernateTemplate;  public Student getStudent(long id) {    return (Student) getHibernateTemplate().get(Student.class, new Long(id));  }  public Collection getAllStudents(){    return getHibernateTemplate().      find("from Student std order by std.lastName, std.firstName");  }  public Collection getGraduatedStudents(){    return getHibernateTemplate().find("from Student std where std.status=1");  }  public Collection findStudents(String lastName) {    return getHibernateTemplate().      find("from Student std where std.lastName like "+ lastName + "%");  }  public void saveStudent(Student std) {    getHibernateTemplate().saveOrUpdate(std);  }  public void removeStudent(Student std) {    getHibernateTemplate().delete(std);  }  public HibernateTemplate getHibernateTemplate() {    return hibernateTemplate;  }  public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {    this.hibernateTemplate = hibernateTemplate;  }}

The DAO class now has the setHibernateTemplate() method to allow Spring to inject the configured HibernateTemplate instance into the DAO object.

Moreover, the DAO class can abandon the HibernateTemplate class and use the SessionFactory instance directly to interact with Hibernate. The following code shows HibernateStudentDao, which now works directly with the SessionFactory object:

package com.packtpub.springhibernate.ch13;import org.hibernate.HibernateException;import org.hibernate.Session;import org.hibernate.Query;import org.hibernate.SessionFactory;import org.springframework.orm.hibernate3.SessionFactoryUtils;import java.util.Collection;public class HibernateStudentDao implements StudentDao {  SessionFactory sessionFactory;  public Student getStudent(long id) {    Session session = SessionFactoryUtils.getSession(this.sessionFactory, true);    try {      return (Student) session.get(Student.class, new Long(id));    } catch (HibernateException ex) {      throw SessionFactoryUtils.convertHibernateAccessException(ex);    } finally {      SessionFactoryUtils.closeSession(session);    }  }  public Collection getAllStudents(){    Session session = SessionFactoryUtils.getSession(this.sessionFactory, true);    try {            Query query = session.createQuery(          "from Student std order by std.lastName, std.firstName");      Collection allStudents = query.list();      return allStudents;    } catch (HibernateException ex) {      throw SessionFactoryUtils.convertHibernateAccessException(ex);    } finally {      SessionFactoryUtils.closeSession(session);    }  }  public Collection getGraduatedStudents(){    Session session = SessionFactoryUtils.getSession(this.sessionFactory, true);    try {      Query query = session.createQuery("from Student std where std.status=1");      Collection graduatedStudents = query.list();      return graduatedStudents;    } catch (HibernateException ex) {      throw SessionFactoryUtils.convertHibernateAccessException(ex);    } finally {      SessionFactoryUtils.closeSession(session);    }  }  public Collection findStudents(String lastName) {    Session session = SessionFactoryUtils.getSession(this.sessionFactory, true);    try {      Query query = session.createQuery(                  "from Student std where std.lastName like ?");      query.setString(1, lastName + "%");      Collection students = query.list();      return students;    } catch (HibernateException ex) {      throw SessionFactoryUtils.convertHibernateAccessException(ex);    } finally {      SessionFactoryUtils.closeSession(session);    }  }  public void saveStudent(Student std) {    Session session = SessionFactoryUtils.getSession(this.sessionFactory, true);    try {      session.save(std);    } catch (HibernateException ex) {      throw SessionFactoryUtils.convertHibernateAccessException(ex);    } finally {      SessionFactoryUtils.closeSession(session);    }  }  public void removeStudent(Student std) {    Session session = SessionFactoryUtils.getSession(this.sessionFactory, true);    try {      session.delete(std);    } catch (HibernateException ex) {      throw SessionFactoryUtils.convertHibernateAccessException(ex);    } finally {      SessionFactoryUtils.closeSession(session);    }  }  public void setSessionFactory(SessionFactory sessionFactory) {    this.sessionFactory = sessionFactory;  }}

In all of the methods above, the SessionFactoryUtils class is used to obtain a Session object. The provided Session object is then used to perform the persistence operation. SessionFactoryUtils is also used to translate HibernateException to DataAccessException in the catch blocks and close the Session objects in the final blocks. Note that this DAO implementation bypasses the advantages of HibernateDaoSupport and HibernateTemplate. You must manage Hibernate's Session manually (as well as exception translation and transaction management) and implement much boilerplate code.

org.springframework.orm.hibernate3.SessionFactoryUtils is a Spring helper class for obtaining Session, reusing Session within transactions, and translating HibernateException to the generic DataAccessException.

This way is absolutely not the way to work with Session in Spring. Always use the HibernateTemplate class to work with Session objects behind the scenes. However, in cases where you need to work directly with Session objects, you can use an implementation of the org.springframework.orm.hibernate3.HibernateCallback interface as the handler to work with Sessions. The following code snippet shows how this approach is:

public void saveStudent(Student std) {  HibernateCallback callback = new HibernateCallback() {   public Object doInHibernate(Session session) throws HibernateException, SQLException {    return session.saveOrUpdate(std);   }  };  getHibernateTemplate().execute(callback);   }

 

In this code, an implicit implementation of HibernateCallback is created and its only doInHibernate() method is implemented. The doInHibernate() method takes an object of Session and returns the result of persistence operation, null if none. The HibernateCallback object is then passed to the execute() method of HibernateTemplate to be executed. The doInHibernate() method just provides a handler to work directly with Session objects that are obtained and used behind the scenes.

Configuring Hibernate in a Spring context

Spring provides the LocalSessionFactoryBean class as a factory for a SessionFactory object. The LocalSessionFactoryBean object is configured as a bean inside the IoC container, with either a local JDBC DataSource or a shared DataSource from JNDI.

The local JDBC DataSource can be configured in turn as an object of org.apache.commons.dbcp.BasicDataSource in the Spring context:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName">    <value>org.hsqldb.jdbcDriver</value>  </property>  <property name="url">    <value>jdbc:hsqldb:hsql://localhost/hiberdb</value>  </property>  <property name="username">    <value>sa</value>  </property>  <property name="password">    <value></value>  </property></bean>

 

In this case, the org.apache.commons.dbcp.BasicDataSource (the Jakarta Commons Database Connection Pool) must be in the application classpath.

Similarly, a shared DataSource can be configured as an object of org.springframework.jndi.JndiObjectFactoryBean. This is the recommended way, which is used when the connection pool is managed by the application server. Here is the way to configure it:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">  <property name="jndiName">    <value>java:comp/env/jdbc/HiberDB</value>  </property></bean>

 

When the DataSource is configured, you can configure the LocalSessionFactoryBean instance upon the configured DataSource as follows:

<bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">    <property name="dataSource">        <ref bean="dataSource"/>    </property>    ...</bean>

 

Alternatively, you may set up the SessionFactory object as a server-side resource object in the Spring context. This object is linked in as a JNDI resource in the JEE environment to be shared with multiple applications. In this case, you need to use JndiObjectFactoryBean instead of LocalSessionFactoryBean:

<bean id="sessionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">  <property name="jndiName">    <value>java:comp/env/jdbc/hiberDBSessionFactory</value>  </property></bean>

 

JndiObjectFactoryBean is another factory bean for looking up any JNDI resource.

When you use JndiObjectFactoryBean to obtain a preconfigured SessionFactory object, the SessionFactory object should already be registered as a JNDI resource. For this purpose, you may run a server-specific class which creates a SessionFactory object and registers it as a JNDI resource.

LocalSessionFactoryBean uses three properties: datasource, mappingResources, and hibernateProperties. These properties are as follows:

  • datasource refers to a JDBC DataSource object that is already defined as another bean inside the container.
  • mappingResources specifies the Hibernate mapping files located in the application classpath.
  • hibernateProperties determines the Hibernate configuration settings.

We have the sessionFactory object configured as follows:

<bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  <property name="dataSource">    <ref bean="dataSource"/>  </property>  <property name="mappingResources">   <list>    <value>com/packtpub/springhibernate/ch13/Student.hbm.xml</value>    <value>com/packtpub/springhibernate/ch13/Teacher.hbm.xml</value>    <value>com/packtpub/springhibernate/ch13/Course.hbm.xml</value>    </list>  </property>  <property name="hibernateProperties">    <props>      <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect      </prop>      <prop key="hibernate.show_sql">true</prop>      <prop key="hibernate.max_fetch_depth">2</prop>    </props>  </property></bean>

 

The mappingResources property loads mapping definitions in the classpath. You may use mappingJarLocations, or mappingDirectoryLocations to load them from a JAR file, or from any directory of the file system, respectively.

It is still possible to configure Hibernate with hibernate.cfg.xml, instead of configuring Hibernate as just shown. To do so, configure sessionFactory with the configLocation property, as follows:

<bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  <property name="dataSource">    <ref bean="dataSource"/>  </property>  <property name="configLocation">    <value>/conf/hibernate.cfg.xml</value>  </property></bean>

 

Note that hibernate.cfg.xml specifies the Hibernate mapping definitions in addition to the other Hibernate properties.

When the SessionFactory object is configured, you can configure DAO implementations as beans in the Spring context. These DAO beans are the objects which are looked up from the Spring IoC container and consumed by the business layer. Here is an example of DAO configuration:

<bean id="studentDao" class="com.packtpub.springhibernate.ch13.HibernateStudentDao">  <property name="sessionFactory">    <ref local="sessionFactory"/>  </property></bean>

 

 

This is the DAO configuration for a DAO class that extends HibernateDaoSupport, or directly uses a SessionFactory property. When the DAO class has a HibernateTemplate property, configure the DAO instance as follows:

<bean id="studentDao" class="com.packtpub.springhibernate.ch13.HibernateStudentDao">  <property name="hibernateTemplate">    <bean class="org.springframework.orm.hibernate3.HibernateTemplate">      <constructor-arg>        <ref local="sessionFactory"/>      </constructor-arg>    </bean>  </property></bean>

 

According to the preceding declaration, the HibernateStudentDao class has a hibernateTemplate property that is configured via the IoC container, to be initialized through constructor injection and a SessionFactory instance as a constructor argument.

Now, any client of the DAO implementation can look up the Spring context to obtain the DAO instance. The following code shows a simple class that creates a Spring application context, and then looks up the DAO object from the Spring IoC container:

package com.packtpub.springhibernate.ch13;    public class DaoClient {  public static void main(String[] args) {     ApplicationContext ctx = new ClassPathXmlApplicationContext("com/packtpub/springhibernate/ch13/applicationContext.xml");    StudentDao stdDao = (StudentDao)ctx.getBean("studentDao");    Student std = new Student();    //set std properties    //save std    stdDao.saveStudent(std);  }}


Spring transaction management

One reason to integrate Hibernate with Spring is transaction management. Spring provides a transaction abstraction layer over the Hibernate transaction API, and enables persistent operations to participate in global transactions. Moreover, Spring provides declarative transaction demarcation, which produces more readable and maintainable Java code. The declarative approach lets us change the transaction strategy easily, without changing the code.

The Spring transaction demarcation API has two classes for working with Hibernate applications:

  • org.springframework.transaction.support.TransactionTemplate for a programmatic approach.
  • org.springframework.transaction.interceptor.TransactionProxyFactoryBean for a declarative approach.

Behind this API, you may use one of Spring's two transaction managers:

  • org.springframework.orm.hibernate3.HibernateTransactionManager: Use this when the application involves a single data source and Hibernate alone is needed. This covers local transactions executed on a single SessionFactory. This manager is commonly used, since most Hibernate applications work with a single database.
  • org.springframework.transaction.jta.JtaTransactionManager: This is Spring's global JTA transaction manager. Use it when the application participates in global transactions in a Java EE environment, in which multiple SessionFactory methods are involved, and transactions are scattered over them.

Note that we can develop DAO classes that are not involved in transaction management. This is an advantage Spring provides for the application, so that all DAO classes work with transactional Session objects provided behind the scenes by the Spring IoC container.

You configure Spring's transactions by setting up the transaction-manager instance as a bean inside the IoC container. The bean configuration depends on which transaction strategy you are using: local or global.

Lets look at the transaction configuration in detail.

Local transactions

When the application uses only a single data source (a single SessionFactory in Hibernate), you can define the transaction manager as an instance of HibernateTransactionManager as follows:

<bean id="transactionManager"      class="org.springframework.orm.hibernate3.HibernateTransactionManager">  <property name="sessionFactory">    <ref bean="sessionFactory"/>  </property></bean>

 

Then, define DAO and Service beans, respectively, as instances of the DAO and service classes. Here is an example:

<bean id="persistenceService" class="com.packtpub.springhibernate.ch13.PersistenceService">    <property name="studentDao">      <ref bean="studentDao"/>    </property>  </bean><bean id="studentDao"class="com.packtpub.springhibernate.ch13.HibernateStudentDao">  <property name="sessionFactory">    <ref bean="sessionFactory"/>  </property></bean>

 

Finally, the DAO instances are wrapped in a proxy transaction. Transactions are cross-cutting concerns that are not dedicated to the function of a particular method. Instead, they are scattered over many persistence methods. With Spring, DAO functionality can be split into two modules:

  • DAO implementations, which perform persistence operations.
  • Transaction advice, which defines how persistence operations are performed in transactions.

Modularizing DAO implementations to carry out persistence operations, and not transaction management, avoids boilerplate transaction-management code in every persistence method. To apply transaction advice to the target methods in the DAO implementations, we need proxy objects.

Each proxy is an object that intermediates between two other objects (a calling object and an invoked object), and applies a concern (a transaction in our case) to the object invocation. Actually, the business layer always works with instances of proxies instead of service objects. Here is an example of the transaction proxy definition:

<bean     id="studentDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  <property name="transactionManager">    <ref bean="transactionManager"/>  </property>  <property name="target">    <ref bean="persistenceService"/>  </property>  <property name="transactionAttributes">    <props>      <prop key="save*">PROPAGATION_REQUIRED</prop>      <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>    </props>  </property></bean>

 

The TransactionProxyFactoryBean object is configured with three properties:

  • transactionManager, declared as an individual bean, is an object which provides an abstraction API between the application code and Hibernate transaction API.
  • target represents the object to which the transaction concern must be applied.
  • transactionAttributes defines how to select the transactional methods. For instance, save* selects all methods of the target object that start with the save word.

In our example, PROPAGATION_REQUIRED and readOnly specify, respectively, how multiple transactions participate, and whether the transaction is allowed to only read the data.

 

Global transactions

You can configure Spring to use global transactions for synchronizing persistent operations that are performed in a Java EE environment across multiple data sources. The configuration process is similar to configuring a local transaction, but you need to define multiple data sources, as well as multiple SessionFactory and DAOs.

The transaction-manager object is now defined as an instance of JtaTransactionManager, instead of HibernateTransactionManager. Here is an example:

<beans>  <!-- the datasource1 declartion, registered to node ds1 on the JNDI tree-->  <bean id="datasource1" class="org.springframework.jndi.JndiObjectFactoryBean">    <property name="jndiName">      <value>java:comp/env/jdbc/ds1</value>    </property>  </bean>  <bean id="datasource2" class="org.springframework.jndi.JndiObjectFactoryBean">    <property name="jndiName">      <value>java:comp/env/jdbc/ds2</value>    </property>  </bean>  <!-- the sessionFactory1 declaration, which uses datasource1-->  <bean id="sessionFactory1"  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">    <property name="mappingResources">      <list>        <value>Student.hbm.xml</value>      </list>    </property>    <property name="hibernateProperties">      <props>        <prop key="hibernate.dialect">          org.hibernate.dialect.MySQLDialect        </prop>      </props>    </property>    <property name="dataSource">      <ref bean="dataSource1"/>    </property>  </bean>  <!-- the sessionFactory2 declartion, which uses datasource2-->  <bean id="sessionFactory2"  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">    <property name="mappingResources">      <list>        <value>Teacher.hbm.xml</value>        <value>Course.hbm.xml</value>      </list>    </property>    <property name="hibernateProperties">      <props>        <prop key="hibernate.dialect">          org.hibernate.dialect.HSQLDialect        </prop>      </props>    </property>    <property name="dataSource">      <ref bean="dataSource2"/>    </property>  </bean>  <!-- TransactionManager declaration -->  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>  <!-- A DAO configuration with the sessionFactory1-->  <bean id="studentDao" class="com.packtpub.springhibernate.ch13.HibernateStudentDao">    <property name="sessionFactory">      <ref bean="sessionFactory1"/>    </property>  </bean>  <!-- A DAO configuration with the sessionFactory2-->  <bean id="teacherDao" class="com.packtpub.springhibernate.ch13.HibernateTeacherDao">    <property name="sessionFactory">      <ref bean="sessionFactory2"/>    </property>  </bean>  <!-- A service instance configuration which reside in the business layer -->  <!-- and works with both StudentDao and TeacherDao instances-->  <bean id="persistenceServiceTarget" class="com.packtpub.springhibernate.ch13.PersistenceService">    <property name="studentDao">      <ref bean="studentDao"/>    </property>    <property name="teacherDao">      <ref bean="teacherDao"/>    </property>  </bean>  <!-- A proxy configuration, which applies the transactions on the DAO methods-->  <bean    id="persistenceService"   class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">    <property name="transactionManager">      <ref bean="transactionManager"/>    </property>    <property name="target">      <ref bean="persistenceServiceTarget"/>    </property>    <property name="transactionAttributes">      <props>        <prop key="save*">PROPAGATION_REQUIRED</prop>        <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>      </props>    </property>  </bean></beans>

 

Alternatively, you can configure the transaction manager as a bean of type JndiObjectFactoryBean in the IoC container. JndiObjectFactoryBean is a factory bean which obtains the transaction-manager object by looking up a JNDI resource. If you choose this strategy, the SessionFactory configuration changes as follows:

<bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  <property name="dataSource">    <ref bean="dataSource"/>  </property>  <property name="jtaTransactionManager">    <ref bean="transactionManager"/>  </property>  <property name="mappingResources">   <list>    <value>com/packtpub/springhibernate/ch13/Student.hbm.xml</value>    <value>com/packtpub/springhibernate/ch13/Teacher.hbm.xml</value>    <value>com/packtpub/springhibernate/ch13/Course.hbm.xml</value>   </list>  </property>  <property name="hibernateProperties">    <props>      <prop key="hibernate.dialect">        org.hibernate.dialect.HSQLDialect      </prop>    </props>  </property></bean>

 

You must also configure a transaction-manager object:

<bean id="transactionManager"class="org.springframework.jndi.JndiObjectFactoryBean">  <property name="jndiName">    <value>java:comp/env/jdbc/mytm</value>  </property></bean>

 

In this way, we configured transactionManager as a bean produced by JndiObjectFactoryBean. This factory bean returns transaction-manager objects by looking up a server-specific JNDI location.

Summary

In this article, you learned about the Data Access Object (DAO) pattern. This pattern allows all interaction with the data tier to be done through specific classes, called DAO classes. According to this pattern, a DAO interface is defined to correspond to each DAO class, defining all persistent operations that the business layer needs. The main goal is to decouple the business layer from the data layer. DAO interfaces are the only references that the business layer uses to perform persistent operations. At this point, Spring is configured to instantiate these references with the actual implementations at runtime.

You can integrate Hibernate with Spring to simplify DAO implementation. Spring provides a transaction abstraction layer on the local transaction API provided by Hibernate, and allows declarative transaction demarcation. Moreover, it converts HibernateException into Spring's generic DataAccessException hierarchy, and allows the use of IoC in the data tier.

Spring supports DAO implementation with two helper classes: org.springframework.orm.hibernate3.HibernateTemplate and org.springframework.orm.hibernate3.support.HibernateDaoSupport. All DAO classes extend HibernateDaoSupport and use HibernateTemplate to perform persistent operations. Spring provides org.springframework.orm.hibernate3.LocalSessionFactoryBean as a factory bean to configure and set up a SessionFactory object in an IoC-style manner. For transaction management, Spring provides org.springframework.orm.hibernate3.HibernateTransactionManager and org.springframework.transaction.jta.JtaTransactionManager for managing local and global transactions, respectively. Moreover, Spring provides org.springframework.transaction.interceptor.TransactionProxyFactoryBean, which acts as a proxy to apply transaction concerns to persistent operations.

 

References

 This article was excerpted from the book, Spring Persistence with Hibernate (Packt Publishing, Nov 2009).

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}