Статьи

Открытая сессия

Шаблон Open Session in View (OSIV) порождает различные мнения в сообществе разработчиков Java. Давайте рассмотрим OSIV и некоторые плюсы и минусы этого паттерна.

Эта проблема

Проблема, которую решает OSIV, заключается в несоответствии между концепцией сеанса Hibernate и ее жизненным циклом, а также тем, как работают многие технологии просмотра на стороне сервера.

В типичном веб-приложении Java сервисный уровень начинается с запроса некоторых данных, необходимых для построения представления. Остальные необходимые данные могут быть загружены позже с условием, что сеанс Hibernate остается открытым — и в этом проблема.

Между моментом, когда метод уровня обслуживания завершает свое выполнение, и моментом отображения представления, Hibernate уже зафиксировал транзакцию и закрыл сеанс.

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

Решение OSIV

OSIV решает эту проблему, гарантируя, что сеанс Hibernate остается открытым вплоть до визуализации представления — отсюда и название шаблона.

Поскольку сеанс остается открытым, больше не возникает исключений LazyInitializationException. Диспетчер сеансов или сущностей остается открытым с помощью фильтра, который добавляется в цепочку обработки запросов.

В случае JPA OpenEntityManagerInViewFilter создаст менеджер сущности в начале запроса, а затем свяжет его с потоком запроса.

Затем будет выполнен сервисный уровень и бизнес-транзакция будет зафиксирована или откатана, но менеджер транзакций не удалит менеджер сущности из потока после фиксации.

Когда рендеринг представления начинается, менеджер транзакций затем проверит, есть ли уже связанный с потоком менеджер сущностей, и если это так, используйте его вместо создания нового.

После обработки запроса фильтр отсоединит менеджер сущностей от потока.

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

Возвращаясь к исходной проблеме

Давайте сделаем шаг назад и вернемся к исходной проблеме: исключение LazyInitializationException. Это исключение действительно проблема? Это исключение также можно рассматривать как предупреждающий знак неверно написанного запроса на уровне сервиса.

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

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

select p FROM Person p left join fetch p.invoices

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

OSIV в проектах, которые я работал

В проектах, в которых я работал, и которые использовали OSIV, мы могли видеть по журналу запросов, что база данных сталкивалась с большим количеством запросов SQL, иногда до такой степени, что разработчикам приходилось отключать протоколирование Hibernate SQL.

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

Плюсы ОСИВ

Основным преимуществом OSIV является то, что он делает работу с ORM и базой данных более прозрачной:

  • Меньше запросов нужно писать вручную
  • Требуется меньше знаний о сеансе Hibernate и о том, как решить LazyInitializationExceptions.

Минусы ОСИВ

OSIV, кажется, легко использовать неправильно и может случайно привести к проблемам с производительностью N + 1 в приложении. На проектах, с которыми я работал, OSIV не работал хорошо в долгосрочной перспективе.

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

Альтернативы OSIV

Помимо решения на уровне приложения для написания пользовательских запросов для предварительной выборки необходимых данных, существуют и другие подходы на уровне инфраструктуры OSIV.

Платформа  Seam Framework  была создана некоторыми из тех же разработчиков, что и Hibernate, и решает проблему, вводя понятие  разговора .

Можете ли вы сообщить мне в комментариях ниже ваши мысли и опыт с OSIV, спасибо за чтение.