使用对象-关系映射持久化数据
11.1 在Spring中集成Hibernate
11.1.1 声明Hibernate的Session工厂
使用Hibernate所需的主要接口是org.hibernate.Session.Session接口提供了基本的数据访问功能。
获取Hibernate Session对象的标准方式是借助于Hibernate SessionFactory接口实现的类。SessionFactory主要负责Hibernate Session的打开、关闭以及管理。
在Spring中,我们要通过Hibernate SessionFactory bean来获取Hibernate SessionFactory。从3.1版本开始,Spring提供三个Session工厂bean供我们选择:
+ org.springframework.orm.hibernate3.LocalSessionFactoryBean
+ org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
+ org.springframework.orm.hibernate4.LocalSessionFactoryBean
11.1.2 构建不依赖于Spring的Hibernate代码
使用上下文Session(Contextual session),而不再使用HibernateTemplate.通过这种方式,会直接将Hibernate SessionFactory装配到Repository中,并使用它来获取Session。 如下:
借助HibernateSession实现不依赖于Spring的Repository
public HibernateSpitterRepository(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
private Session surrentSession(){
return sessionFactory.getCurrentSession();
}
public void count(){
return findAll().size();
}
public Spitter save(Spitter spitter){
Serializable id = currentSession().save(spitter);
return new Spitter((Long)id,
spitter.getUsername(),
spitter.getPassword(),
spitter.getFullName(),
spitter.getEmail(),
spitter.isUpdateByEmail());
}
public Spitter findOne(Long id){
return (Spitter) currentSession().get(Spitter.class,id);
}
public Spitter findByUsername(String username){
return (Spitter) currentSession()
.createCriteria(Spitter.class)
.add(Restrictions.eq("username",username))
.list().get(0);
}
public List<Spitter> findAll(){
return (List<Spitter>) currentSession()
.createCriteria(Spitter.class).list();
}
通过@Inject注解让Spring自动将一个SessionFactory注入到HibernateSpitterRepository的sessionFactory属性中。
在类上使用@Repository注解吗,为我们做两件事:
1. @Repository是Spring的另一种构造性注解,它能够像其他注解一样被Spring的组件扫描所扫描到。
2. 捕获平台相关的异常,然后使用Spring统一非检查型异常的形式重新抛出
11.2 Spring与Java持久化API
在Spring中使用JPA的第一步是要在Spring应用上下文中将实体管理器工厂(entity manager factory)按照bean的形式来进行配置。
11.2.1 配置实体管理器工厂
简单来讲,基于JPA的应用程序需要使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实例管理器:
+ 应用程序管理类型(Application-managed):当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开和关闭实体管理器并在事务中对其进行控制。这种方式的实体管理器适合于不运行在JavaEE容器中的独立应用程序。
+ 容器管理类型(Container-managed):实体管理器由JavaEE创建和管理。应用程序根本不与实体管理器工厂打交道。相反,实体管理器直接通过注入或JNDI来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适用于JavaEE容器,在这种情况下回希望在persistence.xml指定的JPA配置之外保持一些自己对JPA的控制。
上述两种方式实现了同一个EntityManager接口。关键的区别不在于EntityManager本身,而是在于EntityManager的创建和管理方式。
应用程序管理类型的EntityManager是由EntityManagerFactory创建的,而后者是通过PersistenceProvider的createEntityManagerFactory()方法得到的。与此相对,容器管理类型的EntityManagerFactory是通过PersistenceProvider的createContainerManagerFactory()方法得到的.
不管使用哪种EntityManagerFactory,Spring都会负责管理EntityManager。
+ LocalEntityManagerFactoryBean生产应用程序管理类型的EntityManagerFactory
+ LocalContainerEntityManagerFactoryBean生产容器管理类型的EntityManagerFactory
配置应用程序管理类型的JPA
在类路径的META-INF目录下一个名为persistence.xml文件,作用在于定义一个或多个持久化单元(同一个数据源下的一个或多个持久化类)。
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="spitterPU">
<class>com.habuma.spittr.domain.Spitter</class>
<class>com.habuma.spittr.domain.Spittle</class>
<properties>
<property name="toplink.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="toplink.jdbc.url" value="jdbc:hsqldb:hsql://localhost/spitter/spitter" />
<property name="toplink.jdbc.user" value="sa" />
<property name="toplink.jdbc.password" value="" />
</properties>
</persistence-unit>
</persistence>
因为在persistence.xml中包含了大量的配置信息,所以在Spring中需要的配置就很少了。
@Bean
public LocalEntityManagerFactoryBean entityManagerFactoryBean(){
LocalEntityManagerFactoryBean emfb = new LocalEntityManagerFactoryBean();
emfb.setPersistenceUnitName("spitterPU");
return emfb;
}
配置容器管理类型的JPA
从JNDI获取实体管理器工厂
11.2.2 编写基于JPA的Repository
package com.habuma.spittr.persistence;
import *;
@Repository
@Transactional
public class JpaSpitterRepository implements SpitterRepository{
@PersistenceUnit
private EntityManagerFactory emf;//注入EntityManagerFactory
public void addSpitter(Spitter spitter){
emf.createEntityManager().persist(spitter);//创建并使用EntityManager
}
public Spitter getSpitterById(Long id){
return emf.createEntityManager().find(Spitter.class,id);
}
public void saveSpitter(Spitter spitter){
emf.createEntityManager().merge(spitter);
}
}