Implementing DAOs with spring and hibernate

As I go through and implement my DAOs, I noticed that the generic DAO defined by the hibernate site and in books is a good design and has features that I like. However, Spring recommends the use of HibernateTemplate to get uniform exceptions thrown regardless of the underlying data access mechanism. I like that as well. The problem is that when combined with my long conversations (see a previous blog), it all gets quite messy.

However, one option that allows me to write non-HibernateTemplate based DAOs is where you can annotate the DAO with a @Repository attribute then place the following definition in your application contexts where the DAO is defined:

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

If you have a hierarchical set of app contexts, the above bean definition must be placed in each bean definition.

The only issue is whether the DAO needs to keep the session state or not. If so, the the DAOs cannot be used across session objects...and this may be an important design point if I need to load the same object into multiple sessions to better manage long conversations. While it may seem strange to do so, one way to think about why loading the same object into multiple sessions makes sense is that you could use one session to edit the object in a master-detail view while another editor is showing another object but requires the first object as reference data.

I had previously blogged on ways to override some more local methods in Spring to allow the session to be specifically identified. For example, when creating the DAOs for the consuming object (like a presentation model that needs data to provide to a view) you could ensure that the DAO has the right session. Typically in spring, you make sure the DAO has the right session factory...but this is only because it could create a session from the session factory if need be. The HibernateDaoSupport actually needs a session factory to initialize correctly, you could also require your DAO subclass to require an explicit session as well.

If you were to override your DAO to have that long conversation Session object, you may still want to use HibernateTemplate and HibernateCallback machinery since it has other benefits as well or could have future benefits you want to capture for free in spring. Since both the template and callback and actually DAO all have methods that are like getSession(), the question is, which getSession() do you override? You have 3 primary options:


  • Override getSession() in HibernateDaoSupport: This does not, however, propogate to the HibernateTemplate. The HibernateDaoSupport's getSession() mimics HibernateTemplate's getSession(). The other con is that you then have to call getSession() all the time instead of using the HibernateTemplate so it defeats the design point of consistently using spring's machinery.

  • Override getSession() in HibernateCallback() by using a subclass of HibernateCallback. You can do this because HibernateCallback is executed with a execute(Session) called by the HibernateTemplate. You could create a HibernateCallback(Session yourLongSession) with your session in the constructor and a method that takes execute(Session) and just calls execute() which you override each time. The pros is nature integration. The con is that you are still have to be explicit about the session all the time for each call...a bit of burden.

  • Override getSession() in HibernateTemplate: This getSession() is called to get a session to provide to the HibernateCallback() interface. The default getSession() uses SessionFactoryUtils to get the session. If you create a subclass of HibernateDaoSupport and override the HibernateDaoSupport.createHibernateTemplate() method to return a HibernateTemplate subclass that already knows about your session, then everything is transparent to the machinery. The Dao class has to have a setter for that long session anyway, and you can provide the wiring to the template in the setter. Note that the HibernateTemplate does release the session itself so this is highly suspect! However, if you use this overall approach then you should override the HibernateDaoSupport.getSession() and HibernateDaoSupport.releaseSession() to use your long session so no matter what you do in your Dao, all the paths to get a session return our long session. Specifically, you must handle HibernateDaoSupport.releaseSession() so that your session is not released prematurely if a Dao goes directly to the session itself. Interestingly, using HibernateDaoSupport in this fashion is essentially the same as using @Repository and the PersistenceExceptionTranslationPostProcessor bean in your file to ensure that callbacks are properly translated. HibernateDaoSupport already provides ways to set the session factory, the session and convert exceptions (if you are not using the hibernate template) to the spring exception hierarchy. Of course, the only issue with all of this is that the getSession() and releaseSession() methods in HibernateDaoSupport are marked final. Of course, if you create a subclass of the HibernateDaoSupport class you could direct users to your getLongSession() instead. The issues with HibernateDaoSupport have been identified in some Hibernate JIRA issues (search for HibernateDaoSupport).

  • Punt on overriding and write your own native Dao with injection support. Create your own HibernateTemplate subclass so at least you can use that. This is called the natural style in the spring docs.


So it looks like option 3 is one of the best options except for the explicit lifecycle management routines in HibernateTemplate and HibernateDaoSupport (but that's why they are sortof useful in a more general, non-long conversation case).

What to do? In this JIRA issue it mentions that the natural style is perferred if you want to really do custom session handling...after all the template HibernateDaoSupport and HibernateTemplate machinery is designed as convenience functions for spring managed transactions and sessions. These classes do other things as well, but you get the picture. The native style is described in section

12.2.5. Implementing DAOs based on plain Hibernate 3 API
in the spring reference manual.

Comments

Popular posts from this blog

quick note on scala.js, react hooks, monix, auth

zio environment and modules pattern: zio, scala.js, react, query management

user experience, scala.js, cats-effect, IO