Spring with Hibernate persistence and transactions example

02 January 2013
By Gonçalo Marques
In this tutorial you will learn how to implement Hibernate persistence using the Spring framework in a transactional fashion.

Introduction

After reading this tutorial you will be able to implement Hibernate persistence using Spring framework. Additionally you will also use Spring Hibernate transaction manager to manage all the transactional boilerplate code and wiring for you.

This tutorial considers the following software and environment:

  1. Ubuntu 12.04
  2. Maven 3.0.4
  3. JDK 1.7.0.09
  4. Spring 3.2.0
  5. Hibernate 4.1.9
  6. MySQL 5.5.28

Configuration

Configure Maven to get the required Spring dependencies:

Maven pom.xml file referencing required dependencies
<project xmlns="http://maven.apache.org/POM/4.0.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
  http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.byteslounge.spring.tx</groupId>
  <artifactId>com-byteslounge-spring-tx</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>com-byteslounge-spring-tx</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- Define Spring version as a constant -->
    <spring.version>3.2.0.RELEASE</spring.version>
  </properties>

  <dependencies>
  
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
    </dependency>
    
    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-orm</artifactId>
       <version>${spring.version}</version>
    </dependency>
    
    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.2.2</version>
    </dependency>
    
    <dependency>
    	<groupId>javax.persistence</groupId>
    	<artifactId>persistence-api</artifactId>
    	<version>1.0</version>
    </dependency>
    
    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-core</artifactId>
       <version>4.1.9.Final</version>
    </dependency>
    
  </dependencies>
</project>

Now place yourself in the project directory and issue the following command to prepare your project for Eclipse:

mvn eclipse:eclipse

After conclusion you can import the project into Eclipse.



This tutorial will not focus on how to configure a MySQL instance or database but will consider the following table:

MySQL table used in this example
CREATE TABLE USER (
  ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  USERNAME VARCHAR (32) NOT NULL,
  NAME VARCHAR (64) NOT NULL,
  UNIQUE (USERNAME)
);

Entity and DAO

We will need a simple Java class to represent USER table information in the form of a JPA Entity. This class will be the model for this example.

User.java class
package com.byteslounge.spring.tx.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="USER")
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name="ID", nullable = false)
  private int id;
  
  @Column(name="USERNAME", nullable = false)
  private String username;
  
  @Column(name="NAME", nullable = false)
  private String name;
  
  public int getId() {
    return id;
  }
  
  public void setId(int id) {
    this.id = id;
  }

  public String getUsername() {
    return username;
  }
  
  public void setUsername(String username) {
    this.username = username;
  }
  
  public String getName() {
    return name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
  
}


Basically we are defining our model object and the mappings of the User object to the USER table. If you are familiar with JPA this will be straight forward.


Now we define our DAO interface and implementation:

DAO interface
package com.byteslounge.spring.tx.dao;

import java.util.List;

import com.byteslounge.spring.tx.model.User;

public interface UserDAO {

  void insertUser(User user);
  
  User getUserById(int userId);
  
  User getUser(String username);
  
  List<User> getUsers();
}



DAO implementation
package com.byteslounge.spring.tx.dao.impl;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.byteslounge.spring.tx.dao.UserDAO;
import com.byteslounge.spring.tx.model.User;

@Service
public class UserDAOImpl implements UserDAO {

  @Autowired
  private SessionFactory sessionFactory;
  
  @Override
  public void insertUser(User user) {
    sessionFactory.getCurrentSession().save(user);
  }

  @Override
  public User getUserById(int userId) {
    return (User) sessionFactory.
      getCurrentSession().
      get(User.class, userId);
  }
  
  @Override
  public User getUser(String username) {
    Query query = sessionFactory.
      getCurrentSession().
      createQuery("from User where username = :username");
    query.setParameter("username", username);
    return (User) query.list().get(0);
  }
  
  @Override
  @SuppressWarnings("unchecked")
  public List<User> getUsers() {
    Criteria criteria = sessionFactory.
      getCurrentSession().
      createCriteria(User.class);
    return criteria.list();
  }

}

We are basically defining some operations that will be executed over the USER table. Insert a new user, get a user by ID (Primary Key), get a user by it's username and fetching all users.

We use the @Autowired in the SessionFactory property so it gets injected by the Spring container during bean initialization. We will see later how we configure our Hibernate session factory.

The Service bean

Now we need to define the actual service bean that will make use of the DAO we previously defined. You usually implement your business logic in this layer: The service layer. Since this is a very simple example the service layer will just make use of the DAO to interact with the Database and return the results directly to the caller.

Service interface

package com.byteslounge.spring.tx.user;

import java.util.List;

import com.byteslounge.spring.tx.model.User;

public interface UserManager {

  void insertUser(User user);
	
  User getUserById(int userId);
	
  User getUser(String username);
	
  List<User> getUsers();
}




Service implementation

package com.byteslounge.spring.tx.user.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.byteslounge.spring.tx.dao.UserDAO;
import com.byteslounge.spring.tx.model.User;
import com.byteslounge.spring.tx.user.UserManager;

@Service
public class UserManagerImpl implements UserManager {

  @Autowired
  private UserDAO userDAO;
  
  @Override
  @Transactional
  public void insertUser(User user) {
    userDAO.insertUser(user);
  }

  @Override
  @Transactional
  public User getUserById(int userId) {
    return userDAO.getUserById(userId);
  }
  
  @Override
  @Transactional
  public User getUser(String username) {
    return userDAO.getUser(username);
  }

  @Override
  @Transactional
  public List<User> getUsers() {
    return userDAO.getUsers();
  }

}

As we have already stated before it should be in this service layer that the business logic would be implemented. In this simple example we are just using the DAO to interact with the Database and return the results to the caller.

Things to note in this class: The service implementation is annotated with @Service which means that this will be a bean managed by Spring. UserDAO is annotated with @Autowired so it will be injected by the Spring container.

Methods are annotated with @Transactional so the Spring Hibernate transaction manager creates the required transactions and the respective sessions.

Spring configuration file

Now we define the configuration file used for this example:

Spring XML configuration file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd 
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">

  <tx:annotation-driven />
  
  <context:component-scan 
    base-package="com.byteslounge.spring.tx.dao.impl" />
  <context:component-scan 
    base-package="com.byteslounge.spring.tx.user.impl" />

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/TEST" />
    <property name="username" value="testuser" />
    <property name="password" value="testpasswd" />
  </bean>

  <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
    <property name="hibernateProperties">
      <props>
        <prop 
         key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
        <prop key="hibernate.show_sql">true</prop>
      </props>
    </property>
    <property name="packagesToScan" value="com.byteslounge.spring.tx.model" />
  </bean>
  
  <bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager" 
    p:sessionFactory-ref="sessionFactory">
  </bean>

</beans>


Important things to note in the configuration file: We define a datasource bean pointing to our MySQL instance. The sessionFactory bean represents the Hibernate session factory that will create sessions to interact with the database.

We needed to define the packages where the container should look for Entities. In our case it will look for entities in com.byteslounge.spring.tx.model. We also defined the datasource that the session factory will use (property dataSource).

There is also a transactionManager bean. This bean is the Spring Hibernate transaction manager that will handle transaction related boilerplate code and wiring for us. We needed to define the session factory that the transaction manager will use to create sessions (attribute sessionFactory-ref).

tx:annotation-driven element defines that we are declaring transactions using annotations in our classes (remember @Transactional annotations in our service layer?). Finally we define the packages where Spring should look for beans using context:component-scan elements.

Note: In this example we used MySQL as the data repository so we need to specify the correct MySQL Driver in the dataSource bean. This Driver must be in the application classpath when you run your application. Drivers can be usually found in the respective vendor websites. In our case we got it from MySQL website.

Testing the application

Let's create a simple class to test our example:

Simple Main testing class
package com.byteslounge.spring.tx;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.byteslounge.spring.tx.model.User;
import com.byteslounge.spring.tx.user.UserManager;

public class Main 
{
    public static void main( String[] args )
    {
      ApplicationContext ctx = 
        new ClassPathXmlApplicationContext("spring.xml");
      UserManager userManager = 
        (UserManager) ctx.getBean("userManagerImpl");
      
      User user = new User();
      user.setUsername("johndoe");
      user.setName("John Doe");
      
      userManager.insertUser(user);
      
      System.out.println("User inserted!");
      
      user = userManager.getUser("johndoe");
      
      System.out.println("\nUser fetched by username!"
        + "\nId: " + user.getId()
        + "\nUsername: " + user.getUsername()
        + "\nName: " + user.getName());
      
      user = userManager.getUserById(user.getId());
      
      System.out.println("\nUser fetched by ID!"
        + "\nId: " + user.getId()
        + "\nUsername: " + user.getUsername()
        + "\nName: " + user.getName());
      
      List<User> users = userManager.getUsers();
      
      System.out.println("\nUser list fetched!"
          + "\nUser count: " + users.size());

    }
}


When we run our test the following output will be generated:

User inserted!

User fetched by username!
Id: 1
Username: johndoe
Name: John Doe

User fetched by ID!
Id: 1
Username: johndoe
Name: John Doe

User list fetched!
User count: 1


You have successfully integrated Hibernate with Spring. To be more precise you used Spring Hibernate transaction manager to manage your Hibernate sessions and transactions. The source code of this tutorial can be found at the end of this page.

Download source code from this article

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: http://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: