The target is to use JPQL in the code, use hibernate as underlying jpa provider, and use spring to manage transaction.
- This is the project structure:
<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>wx</groupId>
<artifactId>jpa1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jpa1</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.2.14.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0.1</version>
</dependency>
</dependencies>
</project>
- spring 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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/testdb1" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value="wx.jpa1.entity" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan base-package="wx.jpa1" />
</beans>
----- persistence.xml is not required since spring v3.1
----- use spring container to manage transaction propagation
----- use org.springframework.orm.jpa.JpaTransactionManager
- create database and table in mysql
create database testdb1;
use testdb1;
create table student(
stud_id int not null auto_increment,
name varchar(50) not null,
age int,
depart varchar(20),
primary key (stud_id)
)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
- entity class with jpa annotation
package wx.jpa1.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* student entity object
*
*/
@Entity
@Table(name = "student")
public class StudentEO implements Serializable {
private static final long serialVersionUID = 1492053620157953609L;
private Long studId;
private String name;
private int age;
private String depart;
/*
* As an entity object, the default constructor is a must.
*/
public StudentEO() {
}
@Id
@Column(name = "stud_id")
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getStudId() {
return studId;
}
public void setStudId(Long studId) {
this.studId = studId;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "age")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Column(name = "depart")
public String getDepart() {
return depart;
}
public void setDepart(String depart) {
this.depart = depart;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
------------interface IGenericDao ------------
package wx.jpa1.dao;
import java.io.Serializable;
import java.util.List;
public interface IGenericDao<T, PK extends Serializable> {
public T find(PK id);
public void save(T entity);
public T update(T entity);
public void delete(PK id);
public List<T> findAll();
public List<T> findByNamedQuery(String queryName, Object... objects);
}
---------------- implement above interface with jpa ----------
package wx.jpa1.dao;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
public class GenericDaoJpaImpl<T, PK extends Serializable> implements
IGenericDao<T, PK> {
protected Class<T> entityClass;
@PersistenceContext
protected EntityManager entityManager;
@SuppressWarnings("unchecked")
public GenericDaoJpaImpl() {
if (entityClass == null) {
this.entityClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
}
public T find(PK id) {
return this.entityManager.find(entityClass, id);
}
public void save(T entity) {
this.entityManager.persist(entity);
}
public T update(T entity) {
return this.entityManager.merge(entity);
}
public void delete(PK id) {
this.entityManager.remove(this.entityManager.getReference(entityClass,
id));
}
@SuppressWarnings("unchecked")
public List<T> findAll() {
return this.entityManager.createQuery(
"select h from " + this.entityClass.getName() + " h")
.getResultList();
}
public List<T> findByNamedQuery(String queryName, Object... objects) {
// TODO Auto-generated method stub
return null;
}
}
---------------- for particular DAO interface----
package wx.jpa1.dao;
import java.util.List;
import wx.jpa1.entity.StudentEO;
public interface IStudentDao extends IGenericDao<StudentEO, Long> {
public List<StudentEO> findByDepart(String depart);
}
---------------- implement above dao interface -------
package wx.jpa1.dao;
import java.util.List;
import org.springframework.stereotype.Repository;
import wx.jpa1.entity.StudentEO;
@Repository("studentDao")
public class StudentDaoImpl extends GenericDaoJpaImpl<StudentEO, Long>
implements IStudentDao {
public List<StudentEO> findByDepart(String depart) {
// TODO
return null;
}
}
------------- service interface -----------------
package wx.jpa1.service;
import java.util.List;
import wx.jpa1.entity.StudentEO;
public interface IStudentService {
public void registerStudent(StudentEO student);
public List<StudentEO> findAll();
}
------------- implement above interface -------------
package wx.jpa1.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import wx.jpa1.dao.IStudentDao;
import wx.jpa1.entity.StudentEO;
@Service("studentService")
@Transactional
public class StudentServiceImpl implements IStudentService {
@Autowired
@Qualifier("studentDao")
private IStudentDao studentDao;
public IStudentDao getStudentDao() {
return studentDao;
}
public void setStudentDao(IStudentDao studentDao) {
this.studentDao = studentDao;
}
public void registerStudent(StudentEO student) {
studentDao.save(student);
}
public List<StudentEO> findAll() {
return studentDao.findAll();
}
}
-------------------- junit test -----------------
package wx.jpa1;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import wx.jpa1.entity.StudentEO;
import wx.jpa1.service.IStudentService;
@RunWith(org.springframework.test.context.junit4.SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:app-context.xml")
@Transactional
@TransactionConfiguration(defaultRollback=false)
public class IStudentServiceTest {
@Autowired
IStudentService studentService;
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
studentService = null;
}
@Test
public void testRegisterStudent() {
StudentEO student = new StudentEO();
student.setAge(20);
student.setDepart("Computer");
student.setName("Adam");
studentService.registerStudent(student);
}
@Test
public void testQueryStudent() {
List<StudentEO> result = studentService.findAll();
System.out.println(result);
}
}
-------------- test result ------
mysql> select * from student;
+-------------+----------------------------------------------------+-------------+----------------------+
| stud_id | name | age | depart |
+-------------+----------------------------------------------------+-------------+----------------------+
| 5 | Adam | 20 | Computer |
| 6 | Adam | 20 | Computer |
| 7 | Adam | 20 | Computer |
| 8 | Adam | 20 | Computer |
| 11 | John | 20 | Computer |
+-------------+----------------------------------------------------+-------------+----------------------+
5 rows in set (0.00 sec)
Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@1b6aa42e]; rollback [false]
Hibernate:
select
studenteo0_.stud_id as stud_id1_0_,
studenteo0_.age as age2_0_,
studenteo0_.depart as depart3_0_,
studenteo0_.name as name4_0_
from
student studenteo0_
[wx.jpa1.entity.StudentEO@13ef45e0[studId=5,name=Adam,age=20,depart=Computer], wx.jpa1.entity.StudentEO@2d0c94a7[studId=6,name=Adam,age=20,depart=Computer], wx.jpa1.entity.StudentEO@14f3770c[studId=7,name=Adam,age=20,depart=Computer], wx.jpa1.entity.StudentEO@7c0cbf92[studId=8,name=Adam,age=20,depart=Computer]]
Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [TestContext@22dca7d0 testClass = IStudentServiceTest, testInstance = wx.jpa1.IStudentServiceTest@448d5a91, testMethod = testQueryStudent@IStudentServiceTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1c3508c0 testClass = IStudentServiceTest, locations = '{classpath:app-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (2): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@1b6aa42e]; rollback [false]
Hibernate:
insert
into
student
(age, depart, name)
values
(?, ?, ?)
Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [TestContext@22dca7d0 testClass = IStudentServiceTest, testInstance = wx.jpa1.IStudentServiceTest@f292738, testMethod = testRegisterStudent@IStudentServiceTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1c3508c0 testClass = IStudentServiceTest, locations = '{classpath:app-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]