Java持久化API(Java Persistence API,JPA)诞生在EJB2实体Bean的废墟之上,并成为下一代Java持久化标准。JPA是基于POJO的持久化机制,它从Hibernate和Java数据对象(Java Data Object,JDO)上借鉴了很多理念并加入了Java 5注解的特性。
在Spring中使用JPA的第一步是要在Spring应用上下文中将实体管理器工厂(entity manager factory)按照Bean的形式来进行配置。
1.配置实体管理器工厂
基于JPA的应用程序使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实体管理器:
(1)应用程序管理类型:当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开和关闭实体管理器并在事务中对其进行控制。
(2)容器管理类型:实体管理器由Java EE创建和管理。应用程序根本不与实体管理器工厂打交道。相反,实体管理器直接通过注入或JNDI来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适合用于Java EE容器。
以上两种实体管理器实现了同一个EntityManager接口。应用程序管理类型的EntityManager是由EntityManagerFactory创建的,而后者是通过PersistenceProvider的createEntityManagerFactory()方法得到的。与此相对,容器管理类型的EntityManagerFactory是通过PersistenceProvider的createContainerEntityManagerFactory()方法获得的。
不管你希望使用哪种EntityManagerFactory,Spring都会负责管理EntityManager。
这两种实体管理器工厂分别由对应的Spring工厂Bean创建:
LocalEntityManagerFactoryBean生成应用程序管理类型的EntityManagerFactory
LocalContainerEntityManagerFactoryBean生成容器管理类型的EntityManagerFactory
选择应用程序管理类型的还是容器管理类型的EntityManagerFactory,对于基于Spring的应用程序来讲是完全透明的。应用程序管理类型和容器管理类型的实体管理器工厂之间唯一值得关注的区别是,在Spring应用上下文中如何进行配置。
使用应用程序管理类型的JPA
它的绝大部分配置来源于一个名为persistence.xml的配置文件。这个文件必须位于类路径下的META-INF目录下。persistence.xml的作用在于定义一个或多个持久化单元。持久化单元是同一个数据源下的一个或多个持久化类。
参考:
Spitter.java
package com.springinaction.jpa.pojo;
import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "SPITTER", schema = "SPRING")
public class Spitter implements java.io.Serializable
{
private static final long serialVersionUID = -2282127144584390464L;
private BigDecimal id;
private String username;
private String password;
private String fullname;
private String email;
public Spitter()
{}
public Spitter(BigDecimal id, String username, String password, String fullname, String email)
{
this.id = id;
this.username = username;
this.password = password;
this.fullname = fullname;
this.email = email;
}
@Id
@Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
public BigDecimal getId()
{
return this.id;
}
public void setId(BigDecimal id)
{
this.id = id;
}
@Column(name = "USERNAME", nullable = false, length = 20)
public String getUsername()
{
return this.username;
}
public void setUsername(String username)
{
this.username = username;
}
@Column(name = "PASSWORD", nullable = false, length = 20)
public String getPassword()
{
return this.password;
}
public void setPassword(String password)
{
this.password = password;
}
@Column(name = "FULLNAME", nullable = false, length = 50)
public String getFullname()
{
return this.fullname;
}
public void setFullname(String fullname)
{
this.fullname = fullname;
}
@Column(name = "EMAIL", nullable = false, length = 50)
public String getEmail()
{
return this.email;
}
public void setEmail(String email)
{
this.email = email;
}
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_1_0.xsd"
version="1.0">
<persistence-unit name="spitterPU">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.springinaction.jpa.pojo.Spitter</class>
<properties>
<properties>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver" />
<property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
<property name="hibernate.connection.username" value="spring" />
<property name="hibernate.connection.password" value="spring" />
<property name="hibernate.show_sql" value="true" />
</properties>properties>
</persistence-unit>
</persistence>
spring-spitter.xml
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="emf"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="spitterPU" />
</bean>
</beans>
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.3.1.ga</version>
</dependency>
创建应用程序管理类型的EntityManagerFactory都是在persistence.xml中进行的。
在应用程序管理的场景下(不涉及Spring时),完全由应用程序本身来负责获取EntityManagerFactory,这是通过JPA实现的PersistenceProvider做到的。
使用容器管理类型的JPA
将D:\jboss-4.2.2.GA\jboss-4.2.2.GA\lib\concurrent.jar添加到项目中。
spring-spitter.xml
<bean id="emf_annotation"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
<property name="username" value="spring" />
<property name="password" value="spring" />
</bean>
2.编写基于JPA的DAO
Spring对JPA集成也提供了JpaTemplate模板以及对应的支持类JpaDaoSupport。但是,为了实现更纯粹的JPA方式,基于模板的JPA已经被弃用了。
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>3.1.0.GA</version>
</dependency>
<!-- 修改版本 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
spring-spitter.xml
<context:component-scan base-package="com.springinaction.jpa" />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf_annotation" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
需要注意的是em属性上使用了@PersistenceContext注解。简单来讲,这个注解表明需要将一个EntityManager实例注入到em上。为了在Spring中实现EntityManager注入,我们需要在Spring应用上下文中配置一个PersistenceAnnotationBeanPostProcessor。
JpaSpitterDao.java
package com.springinaction.jpa;
import java.math.BigDecimal;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.springinaction.jpa.pojo.Spitter;
@Repository("spitterDao")
@Transactional
public class JpaSpitterDao implements SpitterDAO
{
@PersistenceContext
private EntityManager em;
public void addSpitter(Spitter spitter)
{
em.persist(spitter);
}
public Spitter getSpitterById(int id)
{
return em.find(Spitter.class, new BigDecimal(id));
}
}
Test Demo
@Test
public void test3()
{
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/jpa/spring-spitter.xml");
SpitterDAO dao = (SpitterDAO)ctx.getBean("spitterDao");
Spitter spitter = new Spitter();
spitter.setId(new BigDecimal(11));
spitter.setUsername("Jagger");
spitter.setPassword("123456");
spitter.setFullname("Jagger S Y CHEN");
spitter.setEmail("43970615@XX.com");
dao.addSpitter(spitter);
}
@Test
public void test4()
{
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/jpa/spring-spitter.xml");
SpitterDAO dao = (SpitterDAO)ctx.getBean("spitterDao");
dao.getSpitterById(11);
}