Spring2 JPA Hibernate Tutorial
About this tutorial
This tutorial helps you to set up a simple application using Spring 2, JPA and Hibernate. It guides you to learn the steps involved in installing, configuring, developing, testing and deploying. It covers only the basic functionality of Spring 2, JPA and Hibernate.
Prerequisite
This tutorial requires knowledge or work experience in the following areas.
· Java
· Java
· Spring and Hibernate
· Relational Database Management System (RDBMS)
System Requirements
In order to develop this sample project, the following software is needed.
- The system with at least of 500 MB memory.
- JDK 1.5
- Spring framework with dependencies – 2.5.6 or later can be used.
- Hibernate distribution – 3.3.1 or above
- Hibernate Entity Manager – 3.4.0 or above
- Hibernate Search - 3.1.0 or above
- Lucene -2.4.0
- DB2 Express - C
- Eclipse EE editior
- JBoss – 5.0.0 or later
About the project
This tutorial creates a very simple project. The functionality of this application is to store, retrieve and delete the address information in the Database.
Spring
Spring is a collection of frameworks that provides features to develop distributed applications. It provides the security, transaction, mailing, look up services (JNDI) and other services. The framework is not vendor specific. It can be developed and deployed in standalone and web applications.
The Spring consists of Spring core, Aspect, context, Data Access, ORM and Web, Web MVC. It supports other frameworks to blend in with it. For example, the hibernate can be plugged in for data access and struts for web access. The hibernate is used for data access in this tutorial.
Hibernate
Hibernate is an ORM (Object Relational Mapping) framework to manage the data access. It provides consistent way of accessing and managing data in the relational database. The framework is independent from the database and it hides the complexity of creating the database specific queries.
Java Persistence API
The JPA is an object oriented approach with annotation to the data persistence. It is introduced as part of EE 5.0. But it can be used in java SE also.
Setup Workspace
Creating the workspace is the first step in any project. Point your Eclipse IDE to the workspace folder once it is created. And create a Java project for DAO (Data Access Object) and Web project. The IDE automatically creates the EAR projects and associates the DAO and Web projects with it.
Required libraries
Design domain model
The Address domain consists of the following attributes Id, Number and Street. You can use the following SQL script to create the table in the DB2.
CREATE TABLE ADDRESS ( ID INTEGER NOT NULL, NUM INTEGER, STNAME VARCHAR(25), PRIMARY KEY (ID) ); Define the Java POJO for the above table.
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* @author Elangovan Mohan
*
*/
@Entity // Indicates that it is a table.
public class Address {
@Id // Primary key.
private int id;
@Column(name = "NUM") //Integer column.
private int number;
@Column(name = "STNAME") //String column.
private
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the number
*/
public int getNumber() {
return number;
}
/**
* @param number the number to set
*/
public void setNumber(int number) {
this.number = number;
}
/**
* @return the street
*/
public String getStreet() {
return street;
}
/**
* @param street the street to set
*/
public void setStreet(
this.street = street;
}
Define the service
The service interface provides the data access functionality. It uses the JPA EntityManager to manage the address data. The EntityManager implementation is injected by spring during the server startup.
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.springtutorial.vo.Address;
/**
* @author Elangovan Mohan
*
*/
public class EmployeeServiceImpl implements IEmployeeService {
@PersistenceContext(unitName="application2Jpa") EntityManager entityManager; // The Unit name is defined at persistence.xml.
@Override
public void delete(Address address) {
Address addressToDelete=(Address) entityManager.getReference(Address.class, address.getId());
entityManager.remove(addressToDelete);
}
@Override
public Address findByID(Integer addressId) {
Address address=(Address) entityManager.find(Address.class, addressId);
return address;
}
@Override
public Address save(Address address) {
entityManager.persist(address);
return address;
}
Configure persistence.xml
The persistence.xml is required as per JPA implementation. It describes the persistence unit related information. The Persistence.xml resides under the <
Configure spring application-services.xml
The spring creates and instantiates the beans during the server startup based on the configuration details defined in the service xml. The spring creates the entity manager proxy with entity manager, JPA vendor adapter, data source and persistence unit information. The transaction boundaries can be also declared for the bean.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="myBaseTransaction" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="transactionManager"/>property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIREDprop>
props>
property>
bean>
<bean id="employeeService" parent="myBaseTransaction">
<property name="target">
<bean class="com.springtutorial.dao.EmployeeServiceImpl">
bean>
property>
bean>
<bean id="entityManagerFactory" class=
"org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
bean>
property>
<property name="persistenceXmlLocation">
<value>classpath:/META-INF/persistence.xmlvalue>
property>
<property name="persistenceUnitName" value="application2Jpa" />
bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"/>
<property name="url" value="jdbc:db2://LENOVO-38F85E74:50000/SAMPLE"/>
<property name="username" value="admin" />
<property name="password" value="password" />
bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="dataSource"/>
bean>
beans>
Test Case
The AbstractJPATests can be used to test the service implementation class. The method getConfigLocations informs the Spring runtime to load the application-services.xml. The spring injects the EmployeeServiceImpl proxy at runtime.
import org.springframework.test.jpa.AbstractJpaTests;
import com.springtutorial.dao.EmployeeServiceImpl;
import com.springtutorial.vo.Address;
/**
* @author Elangovan Mohan
*
*/
public class EmployeeServiceTest extends AbstractJpaTests {
public EmployeeServiceImpl employeeService;
/**
* @param employeeService the employeeService to set
*/
public void setEmployeeService(EmployeeServiceImpl employeeService) {
this.employeeService = employeeService;
}
protected String[] getConfigLocations() {
return new String[] { "classpath:/com/springtutorial/dao/application-services.xml" };
}
protected void onSetUpInTransaction() {
Address employee=new Address();
employee.setId(300);
employee.setNumber(3);
employee.setStreet("
employeeService.save(employee);
}
public void testAdd() {
// Address employee=new Address();
// employee.setId(300);
// employee.setNumber(3);
// employee.setStreet("
// employeeService.save(employee);
// Address address=employeeService.findByID(new Long(100));
// assertNotNull(address);
}
Test service implementation
The AbstractJPATests automatically rolls back all the data upon test completion. It makes sure that the data is not persisted in the database. This provides opportunity to test the methods multiple times.
https://www6.software.ibm.com/developerworks/education/j-spring2/section3.html
http://struts.sourceforge.net/struts-spring/index.html
http://www.hibernate.org/hib_docs/entitymanager/reference/en/html/
http://docs.huihoo.com/spring/2.0.x/en/transaction.html#transaction-declarative
http://forum.hibernate.org/viewtopic.php?p=2400801
http://www.netbeans.org/kb/60/web/web-jpa-part2.html
Problems and Troubleshooting
- Server timeout
The default time out is 50ms for the most of the freeware app servers such as jboss or tomcat. You need to increase the time out period at the server console. The time out parameter is configurable in Eclipse 3.4.1 or above versions.
- Jar compatibility
Make sure all the jar files are compatible. For example, slf4j-api-1.5.6.jar and slf4j-log4j12-1.5.6.jar requires log4j-1.2.15.jar.
- java.lang.ClassNotFoundException: <
>
It is the most common problem that you come across when you run the test case. You need to make sure all the compile time and runtime jars are configured at the class path and Java EE module dependencies.
- org.hibernate.LazyInitializationException: could not initialize proxy - no Session
This happens when the EntityManager is not configured correctly. You need to make sure the persistence unit name is defined in the dao and persistence.xml.
5. Can not convert object[your object, proxoy] … happens during the injection….
The possible cause could be the implementation class is configured for the dependency injection at your client code. All you need to do is change the implementation class to the interface.