The DAO with Spring 3 and Hibernate 3

Last Update: 18.05.2013 (5th update)

Table of Contents

1. Overview

This is the first of a series of articles about Persistence with Spring. This article will focus on the configuration and implementation of the persistence layer with Spring 3.1 and Hibernate. For a step by step introduction about setting up the Spring context using Java based configuration and the basic Maven pom for the project, see this.

The Persistence with Spring series:

2. No More Spring Templates

Starting Spring 3.0 and Hibernate 3.0.1, managing the Hibernate Session with Springs HibernateTemplate is no longer necessary. It is now possible to make use of contextual sessions – sessions managed directly by Hibernate and kept active throughout the scope of a transaction.

As a consequence, it is now best practice to use the Hibernate API directly instead of the HibernateTemplate, which will effectively decouple the DAO layer implementation from Spring entirely.

2.1. Exception Translation without the template

One of the responsibilities of HibernateTemplate was exception translation – translating the low level Hibernate exceptions – which tie the API to Hibernate as the single possible ORM – into higher level, generic Spring exceptions.

Without the template to do that, exception translation can still be enabled by annotating the DAOs with the @Repository annotation. That, coupled with a Spring bean postprocessor will advice all @Repository beans with all the implementations of PersistenceExceptionTranslator found in the Spring context – to provide exception translation without using the template.

Exception translation is done through proxies; in order for Spring to be able to create proxies around the DAO classes, these must not be declared final.

2.2. Hibernate Session management without the template

When Hibernate support for contextual sessions came out, the HibernateTemplate essentially became obsolete; in fact, the javadoc of the class has been updated with this advice (bold from the original):

NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can also be coded in plain Hibernate style. Hence, for newly started projects, consider adopting the standard Hibernate3 style of coding data access objects instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.

3. The Spring Java configuration

The Hibernate SessionFactory is set up in the configuration by creating a Spring factory bean to manage it – the AnnotationSessionFactoryBean; this will enable autodetection of the entity classes by classpath scanning. Note that this requires Hibernate 3.2+ and JDK 1.5+.

The alternative is to manually specify all the annotated entity classes to the session factory bean, by using the setAnnotatedClasses method.

@Configuration
@EnableTransactionManagement
public class PersistenceHibernateConfig{

   @Bean
   public AnnotationSessionFactoryBean alertsSessionFactory(){
      AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean();
      sessionFactory.setDataSource( restDataSource() );
      sessionFactory.setPackagesToScan( new String[ ] { "org.rest" } );
      sessionFactory.setHibernateProperties( hibernateProperties() );

      return sessionFactory;
   }
   @Bean
   public DataSource restDataSource(){
      DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setDriverClassName( driverClassName );
      dataSource.setUrl( url );
      dataSource.setUsername( "restUser" );
      dataSource.setPassword( "somePass" );

      return dataSource;
   }
   @Bean
   public HibernateTransactionManager transactionManager(){
      HibernateTransactionManager txManager = new HibernateTransactionManager();
      txManager.setSessionFactory( alertsSessionFactory().getObject() );

      return txManager;
   }
   @Bean
   public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
      return new PersistenceExceptionTranslationPostProcessor();
   }

}

Also note that, for Spring versions before 3.2.x, cglib must be on the classpath for Java @Configuration classes to work; to better understand the need for cglib as a dependency, see this article.

4. The Spring XML configuration

The same Spring configuration with XML:

<bean id="sessionFactory" class=
    "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
   <property name="dataSource" ref="dataSource" />
   <property name="packagesToScan" value="org.rest" />

   <property name="hibernateProperties">
      ...
   </property>
</bean>
<bean id="dataSource" class=
    "org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="${driverClassName}" />
   <property name="url" value="${url}" />
   <property name="username" value="restUser" />
   <property name="password" value="restmy5ql" />
</bean>

<bean id="txManager" class=
    "org.springframework.orm.hibernate3.HibernateTransactionManager">
   <property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />

There is a relatively small difference between the way Spring is configured in XML and the new Java based configuration – in XML, a reference to another bean can point to either the bean or a bean factory for that bean. In Java however, the compiler wouldn’t allow that, and so the SessionFactory is first retrieved from it’s factory and then passed to the transaction manager:

transactionManager.setSessionFactory( this.alertsSessionFactory().getObject() );

5. The Hibernate Properties

Hibernate is configured to work with Spring by using the following Hibernate properties:

hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=false

Note that the MySQL dialect is included as a reference, but any Hibernate supported dialect will do.

6. Potential for Exceptions

6.1. The Transaction Factory

The Hibernate contract for creating transactions is specified by the TransactionFactory interface. In order for Spring to fully manage transactions, the default implementation of this contract – JDBCTransactionFactory – is replaced by default with it’s Spring-aware counterpart – SpringTransactionFactory.

This can also be done manually, in the Hibernate properties (it is however redundant):

transaction.factory_class=org.springframework.orm.hibernate3.SpringTransactionFactory

6.2. The Current Session Context

When the Hibernate SessionFactory is created in the Spring context by it’s factory bean, it will create the CurrentSessionContext. This is the contract for supporting the current session concept and its implementation is decided by analyzing the “hibernate.current_session_context_class” Hibernate property.

Setting this property to “managed” means using the managed implementation for contextual sessions – ManagedSessionContext – which assumes that the current session is managed by an external entity. In our Spring context, that would fail with:

org.springframework.orm.hibernate3.HibernateSystemException: No session currently bound to execution context

Setting the property to “thread” would enable the thread-bound strategy in the Hibernate configuration; this would also conflict with Spring Transaction management and would result in:

org.springframework.orm.hibernate3.HibernateSystemException: persist is not valid without active transaction

To let Spring manage transactions, this property needs to be “org.springframework.orm.hibernate3.SpringSessionContext”; because this is also the default, the explicit definition of the property can be removed.

7. The DAO

Each DAO will be based on an parametrized, abstract DAO class class with support for the common generic operations:

public abstract class AbstractHibernateDAO< T extends Serializable >{
   private Class< T > clazz;

   @Autowired
   SessionFactory sessionFactory;

   public void setClazz( final Class< T > clazzToSet ){
      clazz = clazzToSet;
   }

   public T findOne( final long id ){
      return (T) getCurrentSession().get( clazz, id );
   }
   public List< T > findAll(){
      return getCurrentSession()
       .createQuery( "from " + clazz.getName() ).list();
   }

   public void save( final T entity ){
      getCurrentSession().persist( entity );
   }

   public T update( final T entity ){
      return (T) getCurrentSession().merge( entity );
   }

   public void delete( final T entity ){
      getCurrentSession().delete( entity );
   }
   public void deleteById( final long id ){
      final T entity = findOne( id);
      delete( entity );
   }

   protected final Session getCurrentSession(){
      return sessionFactory.getCurrentSession();
   }
}

A few aspects are interesting here – as discussed, the abstract DAO does not extend any Spring template (such as HibernateTemplate). Instead, the Hibernate SessionFactory is injected directly in the DAO, and will have the role of the main Hibernate API, through the contextual Session it exposes:

this.sessionFactory.getCurrentSession();

Also, note that the entity Class is passed in the constructor to be used in the generic operations:

@Repository
public class FooDAO extends AbstractHibernateDAO< Foo > implements IFooDAO{

   public FooDAO(){
      setClazz(Foo.class );
   }
}

8. The Maven configuration

In addition to the Maven configuration defined in a previous article, the following dependencies are addeed: spring-orm (which also has spring-tx as its dependency) and hibernate-core:

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>3.2.2.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>3.6.10.Final</version>
</dependency>
<dependency>
   <groupId>org.javassist</groupId>
   <artifactId>javassist</artifactId>
   <version>3.17.1-GA</version>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.25</version>
   <scope>runtime</scope>
</dependency>

Note that the MySQL dependency is included as a reference – a driver is needed to configure the datasource, but any Hibernate supported database will do.

9. Conclusion

This article covered the configuration and implementation of the persistence layer with Hibernate and Spring 3.1, using both XML and Java based configuration. The reasons to stop relying on templates for the DAO layer was discussed, as well as possible pitfalls of configuring Spring to manage transactions and the Hibernate Session. The final result is a lightweight, clean DAO implementation, with almost no compile-time reliance on Spring. You can check out the full implementation in the github project.


P.S. If you read this far, you should follow me on Twitter.

, ,

  • Chris Beams

    Eugen,

    Your readers will likely be interested to know that by upgrading to Hibernate 4 (release candidates available now; GA soon), and using Spring 3.1′s orm.hibernate4 package, they can take advantage of the new LocalSessionFactoryBuilder instead of using AnnotationSessionFactoryBean. The former provides a much nicer API for use within @Bean methods and avoids the need to deal with the FactoryBean’s getObject() method. You’ll notice that a HibernateExceptionTranslator is also present in that new package.

    Thanks for the posts, and keep them coming!

  • Dani

    Hi. Regarding session handling, does it still need an OSIV filter?

    • Andy Hahn

      Never use OSIV. Its a terrible pattern. To leave a database connection open for the duration of a web request is ludacris.

  • Gunn Bhatrakarn

    LocalSessionFactoryBean is not implement the PersistentExceptionTranslator for Hibernate 4

    should adding this

    @Bean
    public PersistenceExceptionTranslator exceptionTranslator() {
    return new HibernateExceptionTranslator();
    }

    an error: NoSuchMethodError occur in ‘alertsSessionFactoryBean’

  • Anonymous

    You can retrieve the persistence class this way:

    this.persistentClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];

    so there’s no need for setting the class on the constructor.

  • Alejandro Gomez

    Since you are talking about transactions you should use MySQL5InnoDBDialect in your example hibernate.properties. If the server default engine is MyISAM you won’t get transaction support.
    I know this is just reference code, but maybe someone wants to copy&paste it to try all this out.

  • Jean-Baptiste Nizet

    There is a good reason the Session.merge() method returns an entity: the passed detached entity state is copied to the attached version of the entity, and this attached entity is returned. If your update method ignores the returned value, it forces the caller to find it after, which is not very elegant. Moreover, I find it very confusing to use a different vocabulary than the standard one. Session has an update method, and your AbstractHibernateDAO also has one, but they don’t do the same thing. Same remark for save.

    • baeldung

      I fully agree on update – I changed the method signature in the example. For save however, the semantics of persist do not guarantee that an id is assigned right away, so nothing can be returned from that method. Thanks.

  • Ross Huggett

    Eugen, nice post. Particularly liked the use of generics there.

  • Martin

    Hi, sorry but i am a newbie at Hibernate and Spring and i am using your generic DAO implementation in order to start testing and playing with this stuff.
    I am a little confused with the Preconditions.whatever you are using in the generic DAO implementation. Is that an auxiliary class for checking if the entity about to be used is in the correct state before you actually do the merge, delete or whatever? In order to prevent exceptions? Or is it something different?
    Sorry for my very basic question, but i would like to fully understand what you have have so kindly expressed in such a clear way.

    • baeldung

      Preconditions is a Guava class – I cleaned up the example so that it doesn’t need external libraries.

      Thanks.

  • http://twitter.com/danwattDev Daniel Watt

    Great tutorial. We used this as a guide to get our Restful services up and running a few months ago.

    I have been noticing issues with our services when re-deploying to Tomcat, getting the dreaded out of permgen errors.

    The issue is deep inside of Spring + CGLIB, and has to do with Spring 3.1 + CGLib + no-xml config. one issue: https://jira.springsource.org/browse/SPR-9274

    The problem appears to be in PersistenceHibernateConfig. Two session factories are actually made – one for the @Bean for alertsSessionFactory, and a second for the call to alertsSessionFactory in transactionManager. The second one doesn’t get properly garbage collected on a webapp redeploy.

    Intead of calling alertsSessionFactory().getObject() inside of transactionManager(), pass in the AnnotationSessionFactoryBean. So, it would look like this:

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(AbstractSessionFactoryBean alertsSessionFactory){
    HibernateTransactionManager txManager = new HibernateTransactionManager();
    txManager.setSessionFactory(alertsSessionFactory.getObject() );
    return txManager; }

  • Pingback: Java | Pearltrees

Powered by WordPress. Designed by Woo Themes