[Java] Уровни DAO и Service (JPA / Hibernate + Spring)


Answers

Одно можно сказать наверняка: если вы используете EntityManager на уровне сервиса, вам не нужен слой dao (только один уровень должен знать детали реализации). Кроме того, существуют разные мнения:

  • Некоторые говорят, что EntityManager предоставляет все необходимые функции dao, поэтому они добавляют EntityManager в уровень сервиса.
  • Другие имеют традиционный уровень dao, поддерживаемый интерфейсами (поэтому уровень сервиса не привязан к деталям реализации).

Второй подход более изящный, когда дело доходит до разделения проблем, а также облегчит переключение с одной технологии персистентности на другую (вам просто нужно повторно реализовать интерфейсы dao с новой технологией), но если вы знаете, что ничего изменится, первое проще.

Я бы сказал, если у вас небольшой проект, используйте JPA на уровне сервиса, но в большом проекте используйте выделенный слой DAO.

Question

Я разрабатываю новое приложение, основанное на JPA / Hibernate, Spring и Wicket. Различие между уровнями DAO и Service не так ясно для меня. Согласно Википедии, DAO

объект, который предоставляет абстрактный интерфейс к некоторому типу базы данных или механизма сохранения, предоставляя некоторые конкретные операции, не раскрывая детали базы данных.

Мне было интересно, может ли DAO содержать методы, которые на самом деле не имеют особого отношения к доступу к данным, но проще ли выполнять этот запрос? Например, «получите список всех авиакомпаний, которые работают в определенном наборе аэропортов»? Мне кажется, что это скорее метод уровня сервиса, но я не уверен, что использование JPA EntityManager на уровне сервиса является примером хорошей практики?




Традиционно вы должны писать интерфейсы, которые определяют контракт между вашим уровнем сервиса и уровнем данных. Затем вы записываете реализации, и это ваши DAO.

Вернемся к вашему примеру. Предполагая, что отношения между аэропортом и авиакомпанией много для многих с таблицей, содержащей airport_id и авиакомпанией_ид, у вас может быть интерфейс;

public interface AirportDAO
{
   public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports);
}

.. и вы можете обеспечить выполнение Hibernate этого;

public class HibernateAirportDAO implements AirportDAO
{
   public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports)
   {
      //implementation here using EntityManager.
   }
}

Вы также можете посмотреть список «Список» в вашей организации «Авиакомпания» и определить отношения с аннотацией @ManyToMany JPA. Это устранило бы необходимость использования этого конкретного метода DAO.

Вы также можете просмотреть шаблон Abstract Factory для написания фабрик DAO. Например;

public abstract class DAOFactory
{
   private static HibernateDAOFactory hdf = new HibernateDAOFactory();

   public abstract AirportDAO getAirlineDAO();

   public static DAOFactory getFactory()
   {
      //return a concrete implementation here, which implementation you
      //return might depend on some application configuration settings.
   }
}

public class HibernateDAOFactory extends DAOFactory
{
   private static EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("myPersistenceUnit");

   public static EntityManager getEM()
   {
      return emFactory.createEntityManager();
   }

   public AirportDAO getAirportDAO()
   {
      return new HibernateAirportDAO();
   }
}

Этот шаблон позволяет вашему HibernateDAOFactory иметь одну EMF и поставлять отдельные экземпляры DAO с EM. Если вы не хотите спускаться по дальнему маршруту, то Spring отлично справляется с обработкой экземпляров DAO для вас с инъекцией зависимости.

Изменить: Уточнено несколько допущений.