Ответ 1
Вот что я считаю традиционным:
- Объекты вашего проекта образуют модель домена. Они должны быть повторно использованы и не тесно связаны с технологией персистентности (я вернусь позже о плотной и свободной связи).
- Бизнес-уровень использует модель домена, но также предоставляет услуги и другие продукты.
- Уровень доступа к данным отвечает за сохранение модели домена (сущностей) в постоянном хранилище.
Сущность не должна напрямую обращаться к уровню доступа к данным. Но бизнес-уровень будет таким образом, чтобы загружать и сохранять объекты модели домена.
Если вы сопоставляете это с технологиями Java EE, вы обычно получаете что-то вроде:
- Объекты → POJO с аннотациями Hibernate/JPA. Обратите внимание, что аннотации не подразумевают жесткой связи с JPA/Hibernate, тот же POJO может использоваться где-то еще без Hibernate.
- Бизнес-уровень → Session EJB или Spring
- Уровень доступа к данным → JPA/Hibernate
Это грубый эскиз и есть много возможных вариантов. Вы можете пропустить сессию EJB и реализовать бизнес-уровень другим способом. Вы также можете решить, чтобы бизнес-уровень вызывал сессию JPA/Hibernate Session/EntityManager напрямую, и в этом случае JPA/Hibernate действительно является DAL, или вы можете захотеть обернуть доступ к Session/EntityManager в так называемые объекты доступа к данным (DAO).
Что касается HQL, попробуйте придерживаться того, что переносится, и если вы используете собственный SQL, следуйте соглашениям SQL-92. Если материал станет сложным, возможно, представите DAO. Таким образом, вы знаете, что единственное место, где есть запросы HQL, находится в DAO. Вы также можете сначала реализовать логику запроса "процедурно" в DAO, и если у вас есть проблемы с производительностью, повторите ее реализацию с помощью более сложного запроса HQL.
ИЗМЕНИТЬ
Относительно ваших вопросов в комментарии:
Бизнес-уровень зависит от уровня данных. Если вы хотите, чтобы бизнес-уровень не зависел от Hibernate/JPA, тогда ваш уровень данных должен абстрагироваться от Hibernate/JPA. Если вы используете DAO для своего уровня данных, это будет так. DAO будет "тонким рукописным слоем персистентности над Hibernate" (чтобы взять ваши слова). Я бы представил DAO для всех объектов в вашем случае.
То, что вы задаете, - довольно общий дизайн. Я не могу дать окончательный рецепт для этого и не суммировать все варианты в одном ответе, поскольку это зависит от конкретного случая. Например, мы пока не говорили о проблеме транзакций, которую вы обычно начинаете с бизнес-уровня, но о том, что должен быть осведомлен об уровне данных. Обычно это зависит от используемых технологий и ваших требований.
Тем не менее, вот список ресурсов, которые могут вас заинтересовать: книги Структура архитектуры корпоративных приложений, книга Real World Java EE Patterns - переосмысление лучших практик, книга Разработка домена Driven и более конкретно шаблоны Объект доступа к данным, Паттерн репозитория, Открыть сеанс в режиме просмотра (если это для веб-приложения) и, возможно, Модель анемичного домена.
РЕДАКТИРОВАТЬ 2
Хорошо, еще несколько предложений о транзакциях:
Транзакции должны концептуально управляться в бизнес-слое; определение того, что должно быть сделано в одной единице работы, чтобы быть последовательной, действительно зависит от самой логики приложения.
С EJB3 транзакции могут быть объявлены аннотациями и приложением. сервер управляет этим для вас. Дополнительную информацию см. В этом другом ответе. С помощью Spring вы можете также объявить транзакции декларативно, но я не знаю деталей. В противном случае вам нужно будет начать/остановить транзакцию самостоятельно. Это будет немного отличаться от того, используете ли вы транзакции JDBC или транзакции JTA.
Транзакции также относятся к ленивой загрузке в Hibernate/JPA. Объект, который был ленивым загружен, действительно может быть загружен только в случае текущей транзакции. Если транзакции завершаются на бизнес-уровне, объекты, которые возвращаются на уровень представления, должны быть загружены с высокой нагрузкой.
Чтобы обойти эту проблему, популярным шаблоном для веб-приложений является Открыть сеанс в представлении, о котором я уже говорил. В этом случае слой презентации запускает/останавливает транзакции (что немного неверно концептуально), но отлично работает с ленивой загрузкой.