Spring + JPA + Hibernate example
Introduction
Spring framework supports the persistence layer to be fully implemented through JPA. In this article we will see how to configure the Spring needed components to perform persistence over standard JPA, namely the Persistence Unit, the Entity Manager factory and the Transaction Manager. A fully working stand-alone Spring application is provided as a downloadable sample.
This tutorial considers the following environment:
- Ubuntu 12.04
- JDK 1.7.0.21
- Spring 3.2.5
- Hibernate 4.1.9
The following Maven dependencies are required:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>3.2.5.RELEASE</spring.version> <hibernate.version>4.1.9.Final</hibernate.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>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> </dependencies>
The JPA Entity
We will start the example by defining a simple JPA Entity that will be used through the article:
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; } }
In this example we used MySQL as the RDBMS (database). The entity we just defined is mapped against the following table:
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
USERNAME VARCHAR (32) NOT NULL,
NAME VARCHAR (64) NOT NULL,
UNIQUE (USERNAME)
);
The Spring service and DAO
Now we define a simple DAO that will be used to persist and read our User entities to and from the database. First the DAO interface and then the implementation:
package com.byteslounge.spring.tx.dao; import java.util.List; import com.byteslounge.spring.tx.model.User; public interface UserDAO { void insertUser(User user); List<User> findAllUsers(); }
package com.byteslounge.spring.tx.dao.impl; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import org.springframework.stereotype.Repository; import com.byteslounge.spring.tx.dao.UserDAO; import com.byteslounge.spring.tx.model.User; @Repository public class UserDAOImpl implements UserDAO { @PersistenceContext private EntityManager entityManager; @Override public void insertUser(User user) { entityManager.persist(user); } @Override public List<User> findAllUsers() { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<User> cq = builder.createQuery(User.class); Root<User> root = cq.from(User.class); cq.select(root); return entityManager.createQuery(cq).getResultList(); } }
We just defined our sample DAO containing a couple of operations: One that inserts new users and another that fetches all users from the database.
The Entity Manager is injected through the regular JPA @PersistenceContext annotation.
Now we may proceed with the Spring service definition, first the service interface and then the implementation:
package com.byteslounge.spring.tx.user; import java.util.List; import com.byteslounge.spring.tx.model.User; public interface UserManager { void insertUser(User user); List<User> findAllUsers(); }
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 public List<User> findAllUsers() { return userDAO.findAllUsers(); } }
We defined a Spring service that will provide both the insert and find operations to the service clients.
The DAO is injected into the service through the @Autowired annotation.
The insertUser method is annotated with @Transactional because we are actually modifying the information in the database, so we will need a transaction in order to commit our changes.
The Persistence Unit
As any JPA application we need to define a Persistence Unit. The definition goes into the persistence.xml file:
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL"> <class>com.byteslounge.spring.tx.model.User</class> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" /> </properties> </persistence-unit> </persistence>
We defined the classes (or entities) that will be managed by the persistence unit, in our case is a single entity: The User entity. If we had more entities we could define them individually using multiple class elements.
The persistence provider is defined as Hibernate (we are using Hibernate as the JPA implementation in this tutorial).
Since we are using MySQL as our database we defined the dialect to be used as the MySQL dialect.
Spring configuration
Finally we need to define Spring configuration itself:
<?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/TESTS" /> <property name="username" value="user" /> <property name="password" value="passwd" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="testPU" /> <property name="dataSource" ref="dataSource" /> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
We are configuring Spring to scan certain application packages for Spring managed components through the context:component-scan element (the configured packages are the ones that contain our Service and DAO).
We are also defining that transactions are configured through annotations by using tx:annotation-driven element. Remember that we demarcated the insertUser method to be transactional in our service by using @Transactional annotation.
We also configure a managed dataSource containing our database properties.
The Entity Manager Factory is configured to use the Persistence Unit we defined in the previous section together with the dataSource.
We also define a Transaction Manager that will be used by Spring to manage the required transactions (in this example the transactions are needed to commit the creation of new users).
Testing
Let's define a simple class in order to test our application:
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"); List<User> list = userManager.findAllUsers(); System.out.println("User count: " + list.size()); User user = new User(); user.setUsername("johndoe"); user.setName("John Doe"); userManager.insertUser(user); System.out.println("User inserted!"); list = userManager.findAllUsers(); System.out.println("User count: " + list.size()); } }
When we run the test class it will generate the following output:
User inserted!
User count: 1
The application source code is available for download at the end of this page.