Как следует использовать EntityManager на хорошо отделенном уровне обслуживания и уровне доступа к данным? - PullRequest
10 голосов
/ 22 октября 2011

Отчасти связан с моим другим вопросом Если необработанные аннотированные POJO Hibernate будут возвращены из уровня доступа к данным или интерфейсов вместо этого? , у меня есть опыт создания красиво отделенных слоев, но я не использую Hibernate или J2EE / JPA. Я смотрел на документацию и учебные пособия и озадачен тем, как элегантно использовать EntityManger, так как кажется, что он отвечает как за транзакции (что я хочу сделать на моем уровне обслуживания), так и за методы персистентности (которые я хочу сохранить в уровне доступа к данным). Должен ли я создать его на уровне службы и внедрить его в уровень доступа к данным, или есть лучший способ? Приведенная ниже псевдо-Java показывает примерно то, что я думаю делать.

РЕДАКТИРОВАТЬ: мой псевдокод, приведенный ниже, по сути взят из учебника JPA о гибернации и изменен для разделения слоев и не отражает того, что продукт разрабатывается для запуска в контейнере EJB (Glassfish). В своих ответах, пожалуйста, дайте лучшие практики и примеры кода для кода, работающего в Glassfish или эквивалентном.

MyService
{

  setup()
  {
       EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "Something" ); //is the String you pass in important?
       entityManager = entityManagerFactory.createEntityManager();
  }

  myServiceMethod()
   {
   entityManager.getTransaction().begin();
   MyDao.setEntityManager(entityManagerFactory); 
   MyDao.doSomething();
   MyDao.doSomethingElse();
   entityManager.getTransaction().commit();
   entityManager.close();
   }
 }

MyDao
{
   doSomething()
    {
     entityManager.persist(...); //etc 
    }

}

Ответы [ 3 ]

13 голосов
/ 22 октября 2011

Прежде всего, следует ли вам использовать слой DAO или нет, это спор, который начался с момента появления JPA и EntityManager, который многие люди считают самим DAO. Ответ на этот вопрос зависит от типа приложения, которое вы разрабатываете, но в большинстве случаев вы захотите:

  • Использовать критерии JPA или пользовательские запросы . В этом случае вы, вероятно, не хотите смешивать свою бизнес-логику с созданием запроса. Это привело бы к крупным методам и нарушило бы принцип единственной ответственности .
  • Повторно используйте ваш код JPA в максимально возможной степени . Допустим, вы создали запрос критерия, который возвращает список сотрудников, возраст которых составляет от 40 до 65 лет и которые работают в компании более 10 лет. Возможно, вы захотите повторно использовать этот тип запроса где-то еще на уровне службы, и если это так, то наличие его в службе усложнит эту задачу.

При этом, если все, что у вас есть в приложении, - это операции CRUD, и вы не думаете, что вам может понадобиться повторно использовать какой-либо код JPA, слой DAO, вероятно, является чем-то излишним, поскольку он будет действовать как простая оболочка EntityManager. , что звучит неправильно.

Во-вторых, я бы посоветовал использовать транзакции, управляемые контейнером, когда это возможно. Если вы используете EJB-контейнер, такой как TomEE или JBoss, это позволит избежать большого количества кода, предназначенного для программного создания и управления транзакциями.

В случае, если вы используете контейнер en EJB, вы можете воспользоваться декларативным управлением транзакциями. Примером использования DAO может быть создание компонентов уровня обслуживания как EJB, так и ваших DAO.

@Stateless
public class CustomerService {

    @EJB
    CustomerDao customerDao;

    public Long save(Customer customer) {

        // Business logic here
        return customerDao.save(customer);
    }
}

@Stateless
public class CustomerDao {

    @PersistenceContext(unitName = "unit")
    EntityManager em;

    public Long save(Customer customer) {
        em.persist(customer);
        return customer.getId();
    }

    public Customer readCustomer(Long id) {
            // Criteria query built here
    }

}

В приведенном выше примере конфигурация транзакции по умолчанию ОБЯЗАТЕЛЬНА, что означает, что при отсутствии транзакции в компоненте вызывающей стороны EJB создаст новую транзакцию. Если вызывающая сторона уже создает транзакцию (CustomerService), вызываемый компонент (CustomerDao) наследует транзакцию. Это можно настроить с помощью аннотации @ TransactionAttribute .

Если вы не используете контейнер EJB, я думаю, что ваш пример, приведенный выше, вероятно, будет эквивалентен.

РЕДАКТИРОВАНИЕ : ради простоты я использовал EJB без интерфейса выше, но было бы неплохо использовать интерфейс для них, например, для их создания. более проверяемый.

2 голосов
/ 22 октября 2011

Как правило, вы хотели бы изолировать любой постоянный код на вашем уровне DAO. Так что уровень сервиса даже не должен знать о EntityManager. Я думаю, это нормально, если слой DAO возвращает аннотированные pojos, так как они остаются pojos все еще.

Для управления транзакциями я предлагаю вам взглянуть на Spring ORM . Но если вы решите не использовать Spring или другое решение AOP, вы всегда можете открыть методы, связанные с транзакциями, через DAO, чтобы вызывать их из уровня обслуживания. Это сделает вашу жизнь намного сложнее, но выбор за вами ...

0 голосов
/ 03 февраля 2016

Для простых случаев, таких как getItem (), getEmployee () и т. Д., Лучше внедрить entitymanager непосредственно в использование уровня Service в методе, а не в метод Service, вызывающий метод Dao (в котором есть менеджер сущностей, который)вернуть объект.Это излишне, и DAO просто действует как обертка.Для сложной бизнес-логики, включающей запросы и критерии, позвольте сервисному методу вызвать Dao, который общается с БД.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...