«1. Обзор

В этой статье показано, как реализовать DAO с помощью Spring и JPA. Для базовой конфигурации JPA см. статью о JPA с Spring.

2. Нет больше шаблонов Spring

Начиная с Spring 3.1 JpaTemplate и соответствующий JpaDaoSupport устарели в пользу использования родного Java Persistence API.

Кроме того, оба этих класса относятся только к JPA 1 (из javadoc JpaTemplate):

Note that this class did not get upgraded to JPA 2.0 and never will.

Как следствие, теперь лучше всего использовать Java Persistence API напрямую вместо JpaTemplate.

2.1. Преобразование исключений без шаблона

Одной из обязанностей JpaTemplate было преобразование исключений — преобразование исключений низкого уровня в обобщенные исключения Spring более высокого уровня.

Без шаблона перевод исключений по-прежнему включен и полностью функционален для всех DAO, аннотированных с помощью @Repository. Spring реализует это с постпроцессором bean-компонентов, который будет сообщать всем bean-компонентам @Repository обо всех PersistenceExceptionTranslator, найденных в контейнере.

Также важно отметить, что механизм трансляции исключений использует прокси — чтобы Spring мог создавать прокси вокруг классов DAO, они не должны быть объявлены окончательными.

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 из содержимого и внедряет его.

Постпроцессор персистентности создается либо явно, определяя его в конфигурации, либо автоматически, определяя context:annotation-config или context:component-scan в конфигурации пространства имен.

Также обратите внимание, что класс сущности передается в конструктор для использования в общих операциях:

@Repository
public class FooDAO extends AbstractJPADAO< Foo > implements IFooDAO{

   public FooDAO(){
      setClazz(Foo.class );
   }
}

4. Заключение

В этом руководстве показано, как настроить уровень DAO с помощью Spring и JPA, с использованием конфигурации на основе XML и Java. Мы также обсудили, почему не использовать JpaTemplate и как заменить его на EntityManager. Конечным результатом является легкая, чистая реализация DAO, практически не зависящая от Spring во время компиляции.

Реализацию этого простого проекта можно найти в проекте GitHub — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.