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:
- Ubuntu 12.04
- Maven 3.0.4
- JDK 1.7.0.09
- Spring 3.2.0
- Hibernate 4.1.9
- 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.