Spring with Hibernate Persistence and Transactions Example
Introduction :
------------
Maven 3.0.4
JDK 1.7
Spring 3.2.0
Hibernate 4.1.9
MySQL 5.5.28
Maven Configuration :
=================
Mvn eclipse :eclipse
Table in MySql:
=========================================
Introduction :
------------
Maven 3.0.4
JDK 1.7
Spring 3.2.0
Hibernate 4.1.9
MySQL 5.5.28
Maven Configuration :
=================
<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
Table in MySql:
CREATE TABLE USER ( ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, USERNAME VARCHAR (32) NOT NULL, NAME VARCHAR (64) NOT NULL, UNIQUE (USERNAME) );
ow 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.
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.
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. ThesessionFactory 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 incom.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 usingcontext:component-scan elements.
We needed to define the packages where the container should look for Entities. In our case it will look for entities incom.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 usingcontext:component-scan elements.
Note: In this example we used MySQL as the data repository so we need to specify the correct MySQL Driver in thedataSource 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
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
Thanks for sharing this informative content , Great work
ReplyDeleteLeanpitch provides online training in ICP CAT during this lockdown period everyone can use it wisely.
ICP-CAT certification