You are on page 1of 8

Spring and Hibernate, Simplify the DAO

layer
Spring and Hibernate Simplify the DAO layer

When developing web applications, many people create their data access layer using two
basic design patterns(design pattern meaning an informal description, not to be confused with
the gang of four). The first is to put the responsibility on the DAO class of acquiring the data
source. Approaches may vary from coding this in a super class to externalizing it in a
specialized delegate class. The bottom line is that the DAO cannot provide value to your app
without obtaining a data source directly(e.g. JNDI) or via a delegate class. One of the major
limiting factors here is that your DAO classes are not easily testable outside of the container.
An arguable better implementation would be to parameterize the data source. This allows the
unit test to acquire the data source independent of the DAO class and pass it in upon
execution. This has an upside for the DAO class since it can focus on it's primary
responsibility of providing data. This also makes the DAO class testable outside the container
since the unit test would pass it in. It's a win, win situation right? Well not exactly! The
downside is that now client modules, unit tests in this case, need to know how to obtain a data
source. This is a grave injustice placed on the client code developers. After all, part of the
reason that we have the DAO layer is to simplify data access. Pick your poison: Testable and
inflexible or flexible but difficult to test.

To make things worse, what if you want to swap out your JDBC DAO classes for ones that
use a persistence framework like Hibernate. Hibernate catches my eye because I immensely
dislike writing gobs of SQL. For a Java programmer, Hibernate offers a much more natural
way of persisting objects. Instead of writing JDBC code, hibernate allows me to deal with
POJO's and persist them for me. The bulk of my work lies in maintaing OR Mapping files.
With hibernate, developers working outside the data access layer will not know which classes
are persisted and which are not since the POJO's do not extend or implement anything. So
lets use hibernate in our application them. Unfortunately for us, our make believe application
has DataSource's floating around in method signatures. Since hibernate uses a SessionFactory
object instead of a data source, mass code changes will need to be made to make the
transition. Obviously Hibernate knows about data sources under the covers but client code is
not aware of that. For those of you thinking of a "find and replace" engineering solution, I
hope I never get the opportunity to work with you :) The find and replace approach is similar
to loosening a rusty bolt with a pair of pliers. It might work once, maybe twice, but over time
your bolt's integrity will be compromised and in need of a replacement. The same is true for
your code. It will start to deteriorate over time. I've seen this over and over and over again!
Heck I may have even participated in this kind of macro programming in years past. What are
the options now?

So far I have preached that working with Hibernate is easier and more enjoyable than
working with JDBC directly. This is a personal opinion but one that I know many developers
share. An even better approach is to use the Spring Framework with Hibernate. Bringing
Spring into the mix will allow you to reduce the amount of plumbing code required for
hibernate by a factor of 50% or more. In Spring Live, Matt Raible claims that this code
reduction is in the neighborhood of 75%. I tend to agree with Matt and I have created a
sample application to make my case. My application contains two unit tests(one DAO using
just hibernate and the other using spring and hibernate) that create a 3 field record in a
MySQL database(loosely based on the myusers app from spring live).

First both DAO classes implement the MyRecordDAO interface.

package com.shoesobjects;

import java.io.Serializable;

public class MyRecord implements Serializable {


private Long id = null;
private String firstName = null;
private String lastName = null;

public Long getId() {


return id;
}

public void setId(Long id) {


this.id = id;
}

public String getFirstName() {


return firstName;
}

public void setFirstName(String firstName) {


this.firstName = firstName;
}

public String getLastName() {


return lastName;
}

public void setLastName(String lastName) {


this.lastName = lastName;
}
}

Here is the data access object using just hibernate. Not to bad but lots of cookie cutter
try/catch blocks and redundant opening/closing of sessions. Notice it is 114 lines of code and
would be even larger if I handled exceptions properly like any good programmer would.

package com.shoesobjects.dao;

import com.shoesobjects.MyRecord;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;

import java.util.List;

public class MyRecordDAOHibernate implements MyRecordDAO {


private static SessionFactory sessionFactory = null;

public MyRecordDAOHibernate() {
Configuration cfg = null;
try {
cfg = new Configuration().addClass(MyRecord.class);
} catch (MappingException e) {
e.printStackTrace();
}

try {
sessionFactory = cfg.buildSessionFactory();
} catch (HibernateException e) {
e.printStackTrace();
}
}

private Session getSession() {


Session session = null;
try {
session = sessionFactory.openSession();
} catch (HibernateException e) {
e.printStackTrace();
}
return session;
}

public MyRecord getRecord(Long id) {


Session session = this.getSession();
MyRecord record = null;
try {
record = (MyRecord) session.load(MyRecord.class, id);
} catch (HibernateException e) {
e.printStackTrace();
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
}

return record;
}

public List getRecords() {


Session session = this.getSession();
List list = null;
try {
Query query = session.createQuery("select myrecord from
com.shoesobjects.MyRecord");
list = query.list();
} catch (HibernateException e) {
e.printStackTrace();
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
}

return list;
}

public void saveRecord(MyRecord record) {


Session session = this.getSession();
try {
session.saveOrUpdate(record);
session.flush();
} catch (HibernateException e) {
e.printStackTrace();
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
}
}

public void removeRecord(Long id) {


Session session = this.getSession();
try {
MyRecord record = (MyRecord) session.load(MyRecord.class, id);
session.delete(record);
session.flush();
} catch (HibernateException e) {
e.printStackTrace();
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
}
}
}

Hibernate uses a properties file or xml file for it's configuration information(datasource url,
username, password, database dialect, etc). For simplicity, I'm listing only the necessary
information.

#hibernate.properties
#only used for MyRecordDAOHibernateTest
hibernate.connection.url = jdbc:hsqldb:mem:test
hibernate.connection.username = sa
hibernate.connection.password =
hibernate.dialect = net.sf.hibernate.dialect.HSQLDialect
hibernate.connection.driver_class = org.hsqldb.jdbcDriver
hibernate.hbm2ddl.auto=create
The unit test to exercise this DAO class is listed below. It is a pretty straight forward JUnit
test. The only thing that might look out of the ordinary is that we are instantiating the
MyRecordDAOHibernate() class directly. In practice, it would be beneficial to hide this
behind a Factory. Then you could more easily allow for alternate implementations.

package com.shoesobjects;

import com.shoesobjects.dao.MyRecordDAO;
import com.shoesobjects.dao.MyRecordDAOHibernate;
import junit.framework.Assert;
import junit.framework.TestCase;

public class MyRecordDAOHibernateTest extends TestCase {


private MyRecord record = null;
private MyRecordDAO dao = null;

protected void setUp() throws Exception {


super.setUp();
dao = new MyRecordDAOHibernate();
}

protected void tearDown() throws Exception {


super.tearDown();
dao = null;
}

public void testSaveRecord() throws Exception {


record = new MyRecord();
record.setFirstName("Gavin");
record.setLastName("King");
dao.saveRecord(record);
Assert.assertNotNull("primary key assigned", record.getId());
}
}

The version using Hibernate and Spring has a much cleaner implementation thanks to
Springs. Notice this version doesn't have to deal with creating the SessionFactory or dealing
with opening/closing sessions. The Spring Framework takes care of this under the covers for
you. All you have to do is add the SessionFactory as a needed dependency in Spring's
applicationContext.xml file. Notice this class is only 26 lines of code. Look at how clear and
concise this version is.

package com.shoesobjects.dao;

import com.shoesobjects.MyRecord;
import org.springframework.orm.hibernate.support.HibernateDaoSupport;

import java.util.List;

public class MyRecordDAOHibernateWithSpring extends HibernateDaoSupport


implements MyRecordDAO {
public MyRecord getRecord(Long id) {
return (MyRecord) getHibernateTemplate().get(MyRecord.class, id);
}

public List getRecords() {


return getHibernateTemplate().find("from MyRecord");
}

public void saveRecord(MyRecord record) {


getHibernateTemplate().saveOrUpdate(record);
}

public void removeRecord(Long id) {


Object record = getHibernateTemplate().load(MyRecord.class, id);
getHibernateTemplate().delete(record);
}
}

The applicationContext.xml file contains all the information for Spring's Bean Factory to
instantiate the necessary class es and wire the dependencies. Notice the bean with an id of
myRecordDAO, it has a reference to the bean sessionFactory which is also defined in this
config file.

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property
name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property>
<property name="url"><value>jdbc:hsqldb:mem:test</value></property>
<property name="username"><value>sa</value></property>
<property name="password"><value></value></property>
</bean>

<!-- Hibernate SessionFactory -->


<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="mappingResources">
<list>
<value>MyRecord.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop
key="hibernate.dialect">net.sf.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory
(alternative to JTA) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory"><ref
local="sessionFactory"/></property>
</bean>

<bean id="myRecordDAO"
class="com.shoesobjects.dao.MyRecordDAOHibernateWithSpring">
<property name="sessionFactory"><ref
local="sessionFactory"/></property>
</bean>
</beans>

Here is the JUnit test for Hibernate+Spring implementation of the data access object. Notice
it is just as straight forward as the last unit test but has one noticeable advantage. Look at line
22 where we instantiate the data access object. No concrete implementation is listed, only the
interface. The concrete class is instantiated by Spring's BeanFactory behind the scenes
allowing us to swap out the implementation by editing the applicationContext.xml descriptor.
This flexibility allows our unit test to easily be modified to use a mock implementation
without using command line parameters to the JVC or making code changes.

package com.shoesobjects;

import com.shoesobjects.dao.MyRecordDAO;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyRecordDAOHibernateWithSpringTest extends TestCase {


private ApplicationContext ctx = null;
private MyRecord record = null;
private MyRecordDAO dao = null;

public MyRecordDAOHibernateWithSpringTest() {
// Should put in a parent class that extends TestCase
String[] paths = {"applicationContext.xml"};
ctx = new ClassPathXmlApplicationContext(paths);
}

protected void setUp() throws Exception {


super.setUp();
dao = (MyRecordDAO) ctx.getBean("myRecordDAO");
}

protected void tearDown() throws Exception {


super.tearDown();
dao = null;
}

public void testSaveRecord() throws Exception {


record = new MyRecord();
record.setFirstName("Rod");
record.setLastName("Johnson");
dao.saveRecord(record);
Assert.assertNotNull("primary key assigned", record.getId());
}

In order to run this example, the following steps are required.


1) Install MySQL, login as root
2) Create a database called myrecord
create database myrecord;
3) Create a database user called myrecord with a password of myrecord.
grant all privileges on myrecord.* to myrecord@localhost identified by 'myrecord'
with grant option;
4) Run the unit test's. The database table will be created upon running the test due to the
following line in applicationContext.xml
<prop key="hibernate.hbm2ddl.auto">update</prop>
3) Run the unit tests

IntelliJ IDEA project files are included in the archive. Also, all required jar files are in the lib
directory so you will not have to download anything else.

You might also like