Wednesday, 6 May 2009

Integrating Hibernate with Spring

I tried to learn how to integrate Hibernate with Spring and found very useful information in Spring in Action by Craig Walls.

It was very good book and I found it very informative.

I would like to share few quotations from the book specific to this topic (Integrating Hibernate with Spring).

Before getting started let me tell you about the example I have used in this article.

I am having a very basic table in database


CREATE TABLE sample (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(45) NOT NULL,
city varchar(45) NOT NULL,
PRIMARY KEY (id)
) ;



and here is Sample.hbm.xml


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping >
<class name="hibernate.Sample" table="sample" lazy="false">

<id name="id" column="id" type="java.lang.Long">
<generator class="increment"/>
</id>
<property name="name" type="string"/>
<property name="city" type="string"/>

</class>
</hibernate-mapping>



and here is Sample bean.


public class Sample implements Serializable{

private Long id;
private String name;
private String city;

// getters and setters
}



Now let us get into detail...

The standard way to get a reference to a Hibernate Session object is through an implementation of Hibernate’s SessionFactory interface. Among other things, SessionFactory is responsible for opening, closing, and managing Hibernate Sessions.

The first thing you’ll need to do is to configure a Hibernate session factory bean in Spring.

Spring’s HibernateTemplate provides an abstract layer over a Hibernate Session. HibernateTemplate’s main responsibility is to simplify the work of opening and closing Hibernate Sessions and to convert Hibernate-specific exceptions to one of the Spring ORM exceptions (In the case of Hibernate 2, this means converting a checked HibernateException to an unchecked Spring exception.)

The following XML shows how to configure a HibernateTemplate in Spring:


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



The sessionFactory property takes a reference to an implementation of org.hibernate.SessionFactory. Here you have a few options, depending on
how you use Hibernate to map your objects to database tables.

-> If you are using Hibernate’s classic XML mapping files, you’ll want to use Spring’s LocalSessionFactoryBean.

LocalSessionFactoryBean is a Spring factory bean that produces a local Hibernate SessionFactory instance that draws its mapping metadata from one or more XML mapping files.

how to configure a LocalSessionFactory-Bean that loads the mapping files for the RoadRantz domain objects:


<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>hibernate/Sample.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="show_sql">true</prop>
</props>
</property>
</bean>



-> For annotation-based Hibernate, Spring’s AnnotationSessionFactoryBean works much like LocalSessionFactoryBean, except that it creates a SessionFactory based on annotations in one or more domain classes.

The XML required to configure an AnnotationSessionFactoryBean in Spring is similar to the XML for LocalSessionFactoryBean:


<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>hibernate.Sample</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="show_sql">true</prop>
</props>
</property>
</bean>



The dataSource and hibernateProperties properties serve the same purpose with AnnotationSessionFactoryBean as with LocalSessionFactoryBean. However, instead of configuring one or more mapping files, we must configure AnnotationSessionFactoryBean with one or more classes that are annotated for persistence with Hibernate.

With the HibernateTemplate bean declared and wired with a session factory, we’re ready to start using it to persist and retrieve objects from the database.

Injected HibernateTemplate into HibernateSampleDao.


public class HibernateSampleDAO {

private HibernateTemplate hibernateTemplate;

public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}

}



HibernateSampleDAO accepts a HibernateTemplate reference via setter injection. So configure it.


<bean id="hibSampleDAO" class="hibernate.HibernateSampleDAO">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>



saveSample() method that is used to persist a Sample object to the database:


public void saveSample(Sample sample) {
hibernateTemplate.saveOrUpdate(sample);
}



The saveOrUpdate() method inspects the object to see if its ID field is null. If it is, it must be a new object and thus it is inserted into the database. If it’s not null, it is assumed that it is an existing object and its data is updated.


Now let us look at findSampleByCity() method that uses HibernateTemplate’s find() method to retrieve a Sample by querying by the cityName.


public Sample findSampleByCity(String city) {
List<Sample> results = hibernateTemplate.find("from Sample sample"+
" where city = ?",new Object[] {city});
return results.size() > 0 ? (Sample) results.get(0) : null;
}



And here’s how you might use HibernateTemplate’s load() method to load a specific instance of a Sample by the sample’s ID field:


public Sample getSampleById(Long id) {
return (Sample)hibernateTemplate.load(Sample.class, id);
}



So far, the configuration of HibernateSampleDAO involves four beans. The datasource is wired into the session factory bean (either LocalSessionFactoryBean or AnnotationSessionFactoryBean). The session factory bean is wired into the HibernateTemplate. Finally, the HibernateTemplate is wired into HibernateSampleDAO, where it is used to access the database.

To simplify things slightly, Spring offers HibernateDaoSupport, a convenience DAO support class, that enables you to wire a session factory bean directly into the DAO class. Under the covers, HibernateDaoSupport creates a HibernateTemplate that the DAO can use.

Let’s rework HibernateSampleDAO to use HibernateDaoSupport. The first step is to change HibernateSampleDAO to extend HibernateDaoSupport:


public class HibernateSampleDAO extends HibernateDaoSupport {

}



HibernateSampleDAO no longer needs a HibernateTemplate property as it did in previous example. Instead, you can use the getHibernateTemplate() method to get a HibernateTemplate that HibernateDaoSupport creates for you. So, the next step is to change all the data access methods in HibernateSampleDAO to use getHibernateTemplate().

For example, here’s the saveSample() method updated for the new HibernateDaoSupport-based HibernateSampleDAO:


public void saveSample(Sample sample) {
getHibernateTemplate().saveOrUpdate(sample);
}



HibernateSampleDAO no longer needs a HibernateTemplate reference, so you can remove it. Instead of a Hibernate-Template, you can directly give reference of a Hibernate SessionFactory so that it can produce a HibernateTemplate internally.


<bean id="hibSampleDAO" class="hibernate.HibernateSampleDAO">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>



If you think of extending Spring specific class as an intrusion of Spring into your application code, then you can take advantage of Hibernate 3’s support for contextual sessions to remove Spring-specific dependencies from your DAOs.

Using Hibernate 3 contextual sessions:

Contextual sessions, introduced in Hibernate3, are a way in which Hibernate itself manages one Session per transaction.

There’s no need for HibernateTemplate to ensure this behavior. So, instead of wiring a HibernateTemplate into your DAO, you can wire a Hibernate Session-Factory.


public class HibernateSampleDAO{

private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}



In this new HibernateSampleDAO, a SessionFactory reference is injected into the sessionFactory property. Since SessionFactory comes from the Hibernate API, HibernateSampleDAO no longer depends on the Spring Framework. Instead of using HibernateTemplate to perform persistence operations, you now ask the Session-Factory for the current session.


public void saveSample(Sample sample) {
sessionFactory.getCurrentSession().saveOrUpdate(sample);
}



Configuring this HibernateRantDao is similar to that of HibernateDaoSupport-based version.

Both HibernateDaoSupport and our new pure-Hibernate version of HibernateSampleDao require a Hibernate SessionFactory to be wired into their sessionFactory property. In either case, the sessionFactory bean (which is a SessionFactory-producing LocalSessionFactoryBean or AnnotationSession-FactoryBean) is suitable


<bean id="hibSampleDAO" class="hibernate.HibernateSampleDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>



Note :
-> If you’re using Hibernate 2 then you have no other option than to use HibernateTemplate.

-> The main benefit of Hibernate contextual sessions is that they decouple your DAO implementations from Spring.

-> The primary drawback of contextual sessions is that they throw Hibernatespecific exceptions. Although HibernateException is a runtime exception, the exception hierarchy is specific to Hibernate and not as ORM-agnostic as Spring’s persistence exception hierarchy. This may hinder migration to a different ORM solution.

Hope it will be useful...

11 comments:

Prashant Jalasutram said...

Hi Sneha,

Very nice explanation about integration Hibernate with Spring.

Thanks
Prashant

jishnu said...

Hai sneha,


can u publish any tutorials about, how to handle hibernate array data type in data base

sneha prashant said...

Hi Jishnu,

Try to go through my first blog article "How to store and retrieve BLOB object using hibernate".

I tried to convert BLOB object from database into byte array and vice versa.

It may be useful to you.

Thanks,
Sneha.

trinathchowdary said...

Hi mam i follow u r blog ..where r u these days....please five me u rmail id..my mail is trinath.talluri@gmail.com

I need some help ....just information only..

Sandeep Gupta said...

Nice one.

while using AnnotationSessionFactoryBean

you need to mapping like
@Entity
@Table(name="sample")
public class sample {

}

and then you do not need sample mapping in separate file.

Amit Vakodkar said...

Hi Sneha, Hru, Very Nice explanation, can i get your gmail id please, for further interaction on Spring, etc?.

fyesildal said...

hello Sneha, first of all thanks for your works.

When I was executing the hibernateTemplate.saveOrUpdate(sample) statement (on oracle),it wasn't saving the sample to db but I changed saveOrUpdate to just save(sample),it works.I was taking id field from the user also. I think if the id column is auto incremented and id is taken from the user (contradiction :) ) saveOrUpdate can not be used, am i right ??

Santosh Kumar said...

Nice to see a blog mentioning integrating Hibernate with Spring.

I am going to implement the same concept in my project. I am going through the contents now.

Thank you Sneha. Keep it up.

adam said...

Hi,

we are using springs and hibernate to access database.We have tried with both hibernateTemplate.save(sample)and hibernateTemplate.saveorUpdate(sample)methods to insert the data into database but it is throwing null pointer exception and not taking the above methods.
Please help us.

Regards,
sheethal

ashish bhardwaj said...

Hi Sneha,

Have you tried using JndiRmiProxyFactoryBean instead of RmiProxyFactoryBean.Couple of month back i was implementing ehcache replication and i could do it successfully using rmi but jndi it didn't work and later i figured out some bug has been raised in jira about it ...let me know about it.I tried it without spring.

Nikhil Jasani said...

Hi Sneha,

your explanation is very helpful to me as I am beginner in Spring with Hibernate. Can you please provide me answer of below questions?

-- Which jar files do I need to add in my application to implement above code?

-- If I use Maven then which are the dependencies I need to insert in pom.xml?
As per my understanding I don't need to add any jar file if I use Maven, please correct me if I am wrong.

Thanks in advance.