Подтвердить что ты не робот

Зачем класть слой DAO поверх слоя сохранения (например, JDO или Hibernate)

Объекты доступа к данным (DAO) - это общий шаблон проектирования и рекомендуется Sun. Но самые ранние примеры Java DAO напрямую взаимодействовали с реляционными базами данных - они, по сути, выполняли объектно-реляционное сопоставление (ORM). В настоящее время я вижу DAO поверх зрелых инфраструктур ORM, таких как JDO и Hibernate, и мне интересно, действительно ли это хорошая идея.

Я разрабатываю веб-сервис, используя JDO в качестве уровня сохранения, и рассматриваю вопрос о том, следует ли вводить DAO. Я предвижу проблему при работе с определенным классом, который содержит карту других объектов:

public class Book {
    // Book description in various languages, indexed by ISO language codes
    private Map<String,BookDescription> descriptions;
}

JDO достаточно умен, чтобы сопоставить это с ограничениями внешнего ключа между таблицами "BOOKS" и "BOOKDESCRIPTIONS". Он прозрачно загружает объекты BookDescription (с использованием ленивой загрузки, я считаю), и сохраняет их, когда объект Book сохраняется.

Если бы я должен был ввести "уровень доступа к данным" и написать класс, такой как BookDao, и инкапсулировать весь код JDO внутри этого, то разве эта прозрачная загрузка JDO дочерних объектов не будет обходить слой доступа к данным? Для согласованности не должны ли все объекты BookDescription загружаться и сохраняться через некоторый объект BookDescriptionDao (или метод BookDao.loadDescription)? Однако рефакторинг таким образом заставил бы манипулировать моделью без лишних сложностей.

Итак, мой вопрос: что случилось с вызовом JDO (или Hibernate или какой-либо ORM, который вы представляете) непосредственно на бизнес-уровне? Его синтаксис уже довольно кратким, и он является хранилищем данных-агностиком. Каково преимущество, если таковые имеются, инкапсуляции в объекты доступа к данным?

4b9b3361

Ответ 1

Это зависит от ваших целей слоя. Вы помещаете абстракцию, чтобы предоставить другой набор семантики над другим набором. Как правило, для упрощения таких вещей, как развитие будущего технического обслуживания, существуют дополнительные слои. Но они могли бы использовать и другие виды использования.

Например, слой DAO (или переносимость) по сравнению с ORM-кодом снабжает специализированные функции восстановления и обработки ошибок, которые вы не хотели бы загрязнять бизнес-логику.

Ответ 2

Вы делаете несколько моментов. Но я все же использую слой Dao, вот почему:

  • Доступ к базам данных - это вызовы удаленной системы. Во всех таких случаях (также веб-сервис, ajax и т.д.), Гранулярность взаимодействия должна быть достаточно большой. Многие крошечные звонки убьют производительность. Для этой производительности часто требуется другой вид системы или слоя (здесь слой Дао).

  • Иногда операция сохранения выполняется только для загрузки/сохранения/удаления объекта. Один уникальный Dao (или суперкласс, рассмотрев Generics) может быть ответственным за это, поэтому вам не нужно снова и снова кодировать эти методы.
    Но часто у вас также есть конкретные потребности, такие как запуск определенного запроса, который не создается автоматически ORM. Там вы кодируете свою конкретную потребность с помощью определенного метода Дао (часто используется повторное использование).
    Наличие регулярных и специфических потребностей в одном и том же слое позволяет повторно использовать (например, перехват может гарантировать, что соединение с базой данных будет открыто/поручено, когда это необходимо).

Ответ 3

DAO со временем потерял свой смысл.

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

Было много возможностей для повторного использования, поэтому объект DAO для конкретного объекта может значительно расширить абстрактный DAO, в котором размещается повторно используемый материал, который сам по себе реализовал интерфейс DAO.

Post-J2EE/EJB, шаблоны DataMapper и DataSource (или для простых систем, ActiveRecord) стали популярными для выполнения той же роли. Однако DAO стало модным словом для любого объекта, связанного с сохранением.

В настоящее время термин "DAO", к сожалению, стал синонимом "класса, который позволяет мне общаться с моей базой данных".

С ORM/JPA большая часть обоснования для истинного DAO эпохи J2EE предоставляется из коробки.

В случае последнего шаблона DataSource JPA EntityManager похож на DataSource, но обычно предоставляется через определение PersistenceUnit XML и создается через IoC.

Методы CRUD, которые когда-то жили в DAO или Mapper, теперь могут быть предоставлены ровно один раз с использованием шаблона репозитория. Там нет необходимости в AbstractDAO - продукты ORM достаточно умны, чтобы принять объект() и знать, где он сохраняется.

Ответ 4

При использовании инструмента ORM, такого как JDO или JPA, DAO являются анти-шаблонами. В этом случае создание "уровня доступа к данным" совершенно необязательно и добавит дополнительный код и сложность в кодовую базу, что затрудняет разработку и поддержку.

Основываясь на моем предыдущем опыте, я бы рекомендовал использовать простой статический фасад, скажем Persistence, чтобы предоставить простой в использовании API высокого уровня для операций, связанных с сохранением.

Затем вы можете использовать статический импорт, чтобы получить легкий доступ к этим методам в любом месте, где они полезны. Например, у вас может быть код вроде следующего:


    List<Book> cheapBooks = 
        find("select b from Book where b.price < ?", lowPriceForBooks);
    ...
    Book b = new Book(...);
    persist(b);
    ...
    Book existingBook = load(Book.class, bookId);
    remove(existingBook);
    ...

Вышеприведенный код настолько прост и прост, насколько это возможно, и его можно легко протестировать.

Ответ 5

Одно слово: транзакции

Возьмите ситуацию, когда я должен выполнить две операции обновления данных в одной транзакции. Эти операции вместе образуют логическую единицу работы. Моя бизнес-логика хочет выразить себя в терминах этой единицы работы и не хочет беспокоиться о границах транзакций.

Итак, я пишу DAO. Возьмите этот псевдокод с помощью транзакций Spring и спящего режима:

отредактирован, чтобы удалить HQL, который так обидел @Roger, но который не имел отношения к точке

@Transactional
public void doUnitOfWork() {
  // some persistence operation here
  // some other persistence operation here
}

Моя бизнес-логика вызывает doUnitOfWork(), которая начинает транзакцию, выполняет как операции сохранения, так и затем совершает транзакции. Он не знает и не заботится о транзакции или о том, какие операции выполняются.

Кроме того, если DAO реализует интерфейс с помощью метода doUnitOfWork(), бизнес-логика может кодироваться в интерфейс, облегчая unit test.

Как правило, я всегда переношу свои операции доступа к данным в DAO и ударяю по нему интерфейс.

Ответ 6

Я считаю, что большинство DAO добавляются людьми по историческим (историческим;) причинам. Вы правы в том, что они были в основном предназначены для удобного инкапсулирования SQL-клея, необходимого для выполнения операций CRUD в дни до ORM. В настоящее время с прозрачной настойчивостью их роль в настоящее время в значительной степени избыточна.

Теперь уместны концепции репозиториев и служб:

Repository: Класс, который хранит набор методов запросов, реализованных в специальном коде ORM (например, Hibernate или JDO)

Обычно вы можете создать репозиторий абстрактного базового класса, а затем предоставить конкретную реализацию ORM, в которую вы реализуете все методы запросов в коде, специфичном для вашего ORM. Самое замечательное в этом подходе заключается в том, что вы можете создать реализацию MockRepository, чтобы помочь протестировать ваше приложение, не используя DB.

Услуги: Класс, в котором хранится коллекция методов, которые могут организовать нетривиальные изменения/дополнения к объектной модели (обычно ORM-независимый код).

Это помогает сохранить ваше приложение в значительной степени независимым от ORM - для переноса приложения на другой ORM действительно требуется только реализация нового класса (ов) репозитория, определенного ORM.

Ответ 7

Я полагаю, что шаблон "Класс DAO для каждого объекта" абсолютно избыточен для слоя данных, управляемого ORM. Вместо этого, слой DAO должен состоять из набора наборов методов CRUD с одним набором возможностей, которые работают с произвольными классами сущностей и большим количеством методов, которые выполняют более сложные операции с данными. Если функциональность достаточно велика, то уровень DAO должен быть разделен на несколько классов на основе критериев домена, что делает подход более похожим на сервис-ориентированную архитектуру.

Ответ 8

Цель всего этого введения в слои заключалась в упрощении и простоте обслуживания.

  • Уровень доступа к данным
  • Бизнес-уровень
  • Уровень презентации

Цель 1-го уровня (уровень доступа к данным) заключается в том, чтобы иметь дело с логикой базы данных и препятствовать тому, чтобы бизнес-уровень знал какую-либо деталь БД.
Уровень доступа к данным использует POJO или EJB (DAO) для реализации IoC, а POJOEJB использует сопоставление Hibernate или ORM для фактического взаимодействия с уровнем базы данных.
Итак, если вы хотите, чтобы ваша бизнес-логика не заботилась о том, что и как используется база данных, доступ и обновление, и вы хотите, чтобы DAO позаботился об этом
DAO может поддерживать логику изменения разных таблиц для поддержки работы, совершив ряд вызовов спящего режима.
По сути, вы реализуете многоуровневый подход на уровне доступа к данным, снова разбивая его функциональность на два слоя, например DAO и Hibernate.

Ответ 9

Если вы используете ORM: Наслаждайтесь их Прозрачной поддержкой сохранения! Не используйте DAO для переноса API ORM. Как хорошо сказано здесь, DAO находятся перед ORM. ORM представили концепции из OODBMS, такие как прозрачное сохранение и стойкость по достижимости. Вы должны воспользоваться этим, потому что это сделает вашу жизнь проще и ваш код красивым. Предположим, что вы работаете с отделами и сотрудниками... Одним из вариантов использования может быть создание нового отдела, создание нового сотрудника и добавление сотрудника в отдел... что вы будете делать?

//start persistence context
...
Department dept1 = new Department("department1");
dept1.addEmployee(new Employee("José", 10503f));

em.persist(dept1);
...
//close persistence context

Департамент, Сотрудник и их отношения сохраняются.

Предположим, теперь вам нужно добавить существующего сотрудника и существующего отдела... что бы вы сделали? довольно просто:

//start persistence context
...
Department aDepart = hibernateSession.load(Department.class, dId);
Employee anEmployee = hibernateSession.load(Employee.class, eId);

aDepart.addEmployee(anEmployee);     
...
//close persistence context

Довольно просто благодаря Прозрачной Стойкости и Настойчивости по достижимости, которую реализует Hibernate (как и другие ORM). Нет DAO вообще.

Просто скопируйте модель своего домена и подумайте, что вы сохраняете память. При хорошей стратегии сопоставления ORM будет прозрачно сохраняться, что вы в памяти.

Другие примеры: http://www.copypasteisforword.com/notes/hibernate-transparent-persistence http://www.copypasteisforword.com/notes/hibernate-transparent-persistence-ii

Ответ 10

На самом деле это должно быть проще, чем все эти ответы. Эти шаблоны касаются слоев. Вы не хотите, чтобы круговые ссылки на вас делали слои, которые могут знать только о вещах выше них. Вы хотите, чтобы ваш UICode мог ссылаться на все сервисы и ваш Сервисный код, чтобы иметь возможность ссылаться на все DAO.

  • DAO
  • Сервис
  • Uicode

когда POJO передаются сверху вниз.