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

121

Я видел spring.jpa.open-in-view=trueсвойство в документации Spring Boot для конфигурации JPA.

  • Является ли trueэто свойство значением по умолчанию, если оно вообще не задано ?;
  • Что это на самом деле делает? Я не нашел этому подходящего объяснения;
  • Это заставляет вас использовать SessionFactoryвместо EntityManagerFactory? Если да, как я могу сказать, что я могу использовать его EntityManagerFactoryвместо этого?

Спасибо!

Карлос Альберто
источник

Ответы:

52

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

dunni
источник
На данный момент у меня есть фильтр OpenEntityManagerInViewFilter для управления EntityManager, пока веб-запрос не будет завершен. Этот перехватчик, который вы имели в виду "OpenEntityManagerInViewInterceptor", такой же, как "OpenEntityManagerInViewFilter"? В чем разница между ними? Итак, у меня не было бы больше этого фильтра в контексте моего сервлета для Spring Boot?
Карлос Альберто
1
Перехватчик работает только при использовании DispatcherServlet в Spring (потому что перехватчик - это механизм Spring). Фильтр можно сопоставить со всеми настроенными сервлетами (мы используем его для FacesServlet в одном из наших приложений). Поэтому, если вы используете только DispatcherServlet, вы можете добавить свойство и удалить фильтр, в противном случае используйте фильтр.
dunni
300

Антипаттерн OSIV

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

введите описание изображения здесь

  • 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для того, чтобы справиться с этим сценарием, аннотации влияют на план выборки по умолчанию, поэтому они применяются к каждому бизнес-варианту использования. По этой причине запрос уровня доступа к данным является гораздо более подходящим, поскольку он может быть адаптирован к требованиям текущего варианта использования к выборке данных.

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

Весенняя загрузка и 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, прочтите эту статью .

Влад Михалча
источник
14
В настоящее время регистрируется ПРЕДУПРЕЖДЕНИЕ.
Влад Михалча
Относится ли это к Spring в целом или только к Spring Boot? Можно ли отключить это с помощью класса, аннотированного @ Configuration, вместо установки свойства?
Гордон
2
Это применимо только к Spring Boot. В стандартном Spring вы явно выбираете, какие bean-компоненты использовать или хотите ли вы использовать веб-фильтр, например OSIV. Не знаю, можно ли отключить его с помощью какой-нибудь аннотации. Я знаю только настройку конфигурации.
Влад Михалча
Это не антипаттерн. Он действительно влияет на производительность, иногда отрицательно, часто довольно нейтрально и во многих случаях положительно: если вы действительно хотите начать с ленивого отношения, вам не нужно выполнять запрос во всех случаях и при необходимости можно избежать этого с помощью функции open-in-view.
ymajoros
5
Согласно Википедии, «антипаттерн - это обычная реакция на повторяющуюся проблему, которая обычно оказывается неэффективной и может оказаться крайне контрпродуктивной». Именно это и есть Open Session in View.
Влад Михалча