1. 概述
本文将演示如何使用Spring和JPA实现DAO层。关于核心JPA配置,可参考Spring与JPA集成文章。
2. 告别Spring模板
从Spring 3.1开始,JpaTemplate
和对应的JpaDaoSupport
已被弃用,转而推荐使用原生Java持久化API。
注意:
JpaTemplate
从未升级到JPA 2.0,未来也不会升级。
因此,直接使用Java持久化API已成为最佳实践。
2.1. 无模板的异常转换
JpaTemplate
的核心职责之一是异常转换——将底层异常转换为Spring的高级通用异常。
即使不使用模板,异常转换机制依然有效,适用于所有标注@Repository
的DAO。Spring通过Bean后处理器实现:用容器中所有PersistenceExceptionTranslator
增强@Repository
Bean。
⚠️ 重要提示:异常转换机制依赖代理,因此DAO类**不能声明为final
**。
3. DAO实现
首先实现所有DAO的基类——使用泛型的抽象类:
public abstract class AbstractJpaDAO< T extends Serializable > {
private Class< T > clazz;
@PersistenceContext
EntityManager entityManager;
public final void setClazz( Class< T > clazzToSet ){
this.clazz = clazzToSet;
}
public T findOne( long id ){
return entityManager.find( clazz, id );
}
public List< T > findAll(){
return entityManager.createQuery( "from " + clazz.getName() )
.getResultList();
}
public void create( T entity ){
entityManager.persist( entity );
}
public T update( T entity ){
return entityManager.merge( entity );
}
public void delete( T entity ){
entityManager.remove( entity );
}
public void deleteById( long entityId ){
T entity = findOne( entityId );
delete( entity );
}
}
关键点在于**EntityManager
的注入方式**——使用标准@PersistenceContext
注解。底层由PersistenceAnnotationBeanPostProcessor
处理:解析注解、获取JPA实体管理器并注入。
该后处理器可通过以下任一方式激活:
- 显式定义Bean
- 在XML配置中声明
context:annotation-config
- 在XML配置中声明
context:component-scan
实体Class
通过构造函数传入,用于泛型操作:
@Repository
public class FooDAO extends AbstractJPADAO< Foo > implements IFooDAO{
public FooDAO(){
setClazz(Foo.class );
}
}
4. 总结
本文展示了如何使用Spring和JPA搭建DAO层(支持XML和Java配置)。我们讨论了弃用JpaTemplate
的原因,以及如何用EntityManager
替代它。最终实现了一个轻量级、简洁的DAO层,编译时几乎不依赖Spring。
完整示例代码见[GitHub项目](https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-jpa "DAO with JPA - example project)(Maven项目,可直接导入运行)。