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

Что это за spring.jpa.open-in-view = true в Spring Boot?

Я видел в Spring Загрузочную документацию это свойство для конфигурации JPA spring.jpa.open-in-view=true. Кстати, он был установлен как истинный, так это значение по умолчанию?

Что это значит? Я не нашел объяснения этого поведения.

Следует ли вместо этого использовать Hibernate SessionFactory EntityManagerFactory? Если да, как я могу установить EntityManagerFactory?

Оцените любую помощь.

Спасибо!

4b9b3361

Ответ 1

Это свойство зарегистрирует OpenEntityManagerInViewInterceptor, который регистрирует EntityManager в текущем потоке, поэтому у вас будет тот же EntityManager, пока веб-запрос не будет завершен. Это не имеет никакого отношения к Hibernate SessionFactory и т.д.

Ответ 2

Анти-шаблон OSIV

Вместо того, чтобы позволить бизнес-уровню решить, как лучше всего выбрать все ассоциации, которые необходимы для уровня View, OSIV (Open Session in View) заставляет постоянный контекст оставаться открытым, чтобы уровень View мог инициировать инициализацию Proxy, как показано по следующей схеме.

enter image description here

  • OpenSessionInViewFilter вызывает метод openSession базового SessionFactory и получает новый Session.
  • Session связан с TransactionSynchronizationManager.
  • OpenSessionInViewFilter вызывает doFilter ссылки на объект javax.servlet.FilterChain, и запрос дополнительно обрабатывается
  • Вызывается DispatcherServlet, и он направляет HTTP-запрос на базовый PostController.
  • PostController вызывает PostService, чтобы получить список Post сущностей.
  • PostService открывает новую транзакцию, а HibernateTransactionManager повторно использует тот же Session, который был открыт OpenSessionInViewFilter.
  • PostDAO выбирает список сущностей Post без инициализации ленивых ассоциаций.
  • PostService фиксирует основную транзакцию, но Session не закрыт, потому что он был открыт снаружи.
  • DispatcherServlet начинает рендеринг пользовательского интерфейса, который, в свою очередь, перемещается по ленивым ассоциациям и запускает их инициализацию.
  • OpenSessionInViewFilter может закрыть Session, и исходное соединение с базой данных также освобождается.

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

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

Больше нет разделения интересов, потому что операторы генерируются как сервисным уровнем, так и процессом рендеринга пользовательского интерфейса. Для написания интеграционных тестов, в которых утверждается количество генерируемых операторов, необходимо пройти через все уровни (веб, сервис, DAO), пока приложение развертывается в веб-контейнере. Даже при использовании базы данных в памяти (например, HSQLDB) и облегченного веб-сервера (например, Jetty) эти интеграционные тесты будут выполняться медленнее, чем если бы слои были разделены, а внутренние интеграционные тесты использовали базу данных, в то время как Фронтальные интеграционные тесты вообще издевались над уровнем сервиса.

Уровень пользовательского интерфейса ограничен навигационными ассоциациями, которые, в свою очередь, могут вызвать проблемы с N + 1 запросами. Хотя Hibernate предлагает @BatchSize для извлечения связей в пакетах и FetchMode.SUBSELECT, чтобы справиться с этим сценарием, аннотации влияют на план выборки по умолчанию, поэтому они применяются к каждому бизнесу случай использования. По этой причине запрос уровня доступа к данным является гораздо более подходящим, поскольку он может быть адаптирован к текущим требованиям извлечения данных варианта использования.

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

Spring Boot и OSIV

К сожалению, OSIV (Open Session in View) по умолчанию включен в Spring Boot, и OSIV действительно плохая идея с точки зрения производительности и масштабируемости.

Поэтому убедитесь, что в файле конфигурации application.properties есть следующая запись:

spring.jpa.open-in-view=false

Это отключит OSIV, так что вы сможете правильно обрабатывать LazyInitializationException.

Начиная с версии 2.0, Spring Boot выдает предупреждение, когда OSIV включен по умолчанию, поэтому вы можете обнаружить эту проблему задолго до того, как она затронет производственную систему.

Подробнее о OSIV читайте в этой статье.