Глава 2. Архитектура

Оглавление
  1. 2.1. Обзор
    1. 2.1.1. Минимальная архитектура
    2. 2.1.2. Комплексная архитектура
    3. 2.1.3. Основной API
  2. 2.2. Контекстные сессии

2.1. Обзор

На приведённой ниже диаграмме представлен высокоуровневый вид архитектуры Hibernate:

Высокоуровневый вид архитектуры Hibernate

К сожалению, мы не можем предоставить подробный обзор всех возможных архитектур времени выполнения. Hibernate достаточно гибкий, чтобы его можно было использовать многими способами во многих, многих архитектурах. Мы, однако, проиллюстрируем 2 конкретные, так как они являются «крайностями».

2.1.1. Минимальная архитектура

«Минимальная» архитектура имеет приложение, управляющее своими собственными JDBC-соединениями и обеспечивающее их подключения к Hibernate; кроме того, приложение управляет транзакциями для себя. Этот подход использует минимальный набор обращений к Hibernate API.

Минимальная архитектура

2.1.2. Комплексная архитектура

«Комплексная» архитектура абстрагирует приложение от базового JDBC/JTA API и позволяет Hibernate управлять деталями.

Комплексная архитектура

2.1.3. Основной API

Ниже приведено краткое описание некоторых элементов API, изображённых на предыдущих диаграммах (вы увидите их более подробно в последующих главах).

SessionFactory (org.hibernate.SessionFactory)
Потокобезопасный, неизменяемый кэш скомпилированных отображений для одной базы данных. Фабрика для экземпляров org.hibernate.Session. Клиент org.hibernate.connection.ConnectionProvider. Опционально поддерживает кэш второго уровня данных, которые можно повторно использовать между транзакциями на уровне процесса или кластера.
Session (org.hibernate.Session)
Однопоточный, недолговечный (short-lived) объект, представляющий собой соглашение между приложением и постоянным хранилищем. Обёртка JDBC java.sql.Connection. Фабрика для org.hibernate.Transaction. Поддерживает кэш первого уровня постоянных (persistent) объектов и коллекций приложения; этот кэш используется при навигации по графу объекта или поиска объектов по идентификатору.
Постоянные (persistent) объекты и коллекции
Недолговечные (short-lived) однопоточные объекты, содержащие постоянное состояние и бизнес-функционал. Это могут быть обычные JavaBeans/POJO объекты. Они связаны именно с одним org.hibernate.Session. Как только org.hibernate.Session будет закрыт, они будут отсоединены (detached) и свободны для использования в любом уровне приложения (например, непосредственно как объекты передачи данных в презентацию и из презентации). Глава 11. Работа с объектами обсуждает переходные (transient), постоянные (persistent) и отсоединённые (detached) состояния объектов.
Переходные (transient) и отсоединённые (detached) объекты и коллекции
Экземпляры постоянных (persistent) классов, которые в настоящее время не связаны с org.hibernate.Session. Они, возможно, были созданы экземпляром приложения и еще не сохранены, или они, возможно, были созданы экземпляром закрытого org.hibernate.Session. Глава 11. Работа с объектами обсуждает переходные (transient), постоянные (persistent) и отсоединённые (detached) состояния объектов.
Transaction (org.hibernate.Transaction)
(Опционально) Однопоточный, недолговечный (short-lived) объект, используемый приложением для указания атомарных единиц работы. Он абстрагирует приложение от базовой транзакции JDBC, JTA или CORBA. Org.hibernate.Session может охватывать несколько org.hibernate.Transactions в некоторых случаях. Однако разграничение транзакций, использующее базовый API или org.hibernate.Transaction, никогда не является обязательным.
ConnectionProvider (org.hibernate.connection.ConnectionProvider)
(Опционально). Фабрика и пул соединений JDBC. Он абстрагирует приложение из основного javax.sql.DataSource или java.sql.DriverManager. Он не распространяется на приложение, но может быть расширен и/или реализован разработчиком.
TransactionFactory (org.hibernate.TransactionFactory)
(Опционально) Фабрика для org.hibernate.Transaction. Не распространяется на приложение, но может быть расширена и/или реализована разработчиком.
Расширяемые интерфейсы
Hibernate предлагает ряд дополнительных интерфейсов расширения, которые вы можете реализовать для настройки поведения вашего уровня персистентности. Подробнее см. В документации по API.

2.2. Контекстные сессии

Большинство приложений, использующих Hibernate, нуждаются в какой-то форме «контекстной» сессии, где данная сессия действует во всей области данного контекста. Однако во всех приложениях определение того, что представляет собой контекст, обычно отличается; различные контексты определяют разные области применения понятия «текущий». Приложения, использующие Hibernate до версии 3.0, имели тенденцию использовать либо вспомогательные классы на основе ThreadLocal, такие как HibernateUtil, либо использовать сторонние структуры, такие как Spring или Pico, которые предоставляли контекстные сессии на основе прокси/перехвата (proxy/interception).

Начиная с версии 3.0.1 в Hibernate был добавлен метод SessionFactory.getCurrentSession(). Первоначально это предполагаемое использование транзакций JTA, где транзакция JTA определяла как область видимости, так и контекст текущей сессии. Учитывая зрелость многочисленных автономных реализаций JTA TransactionManager, большинство, если не все, приложения должны использовать управление транзакциями JTA, независимо от того, развертываются ли они в контейнере J2EE. Исходя из этого, контекстные сессии на основе JTA — все, что вам нужно использовать.

Однако, начиная с версии 3.1, обработка SessionFactory.getCurrentSession() теперь подключаема. С этой целью был добавлен новый интерфейс расширения org.hibernate.context.spi.CurrentSessionContext и новый параметр конфигурации hibernate.current_session_context_class, позволяющие подключать область и контекст определения текущих сессий.

См. Javadocs, где для интерфейса org.hibernate.context.spi.CurrentSessionContext подробно описан его контракт. Он определяет единственный метод currentSession(), с помощью которого реализация отвечает за отслеживание текущего контекста сессии. "Из коробки" Hibernate предоставляет три реализации этого интерфейса:

Первые две реализации предоставляют модель программирования «одна сессия — одна база данных». Или по-другому: сессия-за-запрос (session-per-request). Начало и конец сессии Hibernate определяется продолжительностью транзакции базы данных. Если вы используете программное разделение транзакций в простой JSE без JTA, вам рекомендуется использовать Hibernate Transaction API, чтобы скрыть базовую систему транзакций из вашего кода. Если вы используете JTA, вы можете использовать интерфейсы JTA для разделения транзакций. Если код выполняется в контейнере EJB, который поддерживает CMT, границы транзакций определяются декларативно, и вам не нужны никакие операции разделения транзакций или сессий в вашем коде. Более подробную информацию и примеры кода см. в главе 13 «Транзакции и параллельное выполнение».

Параметр конфигурации hibernate.current_session_context_class определяет, какая реализация org.hibernate.context.spi.CurrentSessionContext должна использоваться. Для обратной совместимости, если этот параметр конфигурации не установлен, а настроен org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform, Hibernate будет использовать org.hibernate.context.internal.JTASessionContext. Как правило, значение этого параметра просто называет класс реализации. Однако для трех готовых реализаций существует три соответствующих коротких имени: «jta», «thread» и «managed».