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项目,可直接导入运行)。


原始标题:The DAO with JPA and Spring