Для более подробного описания вы можете прочитать мою статью Open Session In View Anti-Pattern . В противном случае, вот краткое изложение того, почему вам не следует использовать Open Session In View.
Open Session In View использует неправильный подход к извлечению данных. Вместо того, чтобы позволить бизнес-уровню решать, как лучше всего получить все ассоциации, необходимые для уровня представления, он заставляет контекст сохранения оставаться открытым, чтобы уровень представления мог запускать инициализацию прокси.
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
для того, чтобы справиться с этим сценарием, аннотации влияют на план выборки по умолчанию, поэтому они применяются к каждому бизнес-варианту использования. По этой причине запрос уровня доступа к данным является гораздо более подходящим, поскольку он может быть адаптирован для требований текущего варианта использования к выборке данных.
И последнее, но не менее важное: соединение с базой данных может поддерживаться на протяжении фазы рендеринга пользовательского интерфейса (в зависимости от режима освобождения соединения), что увеличивает время аренды соединения и ограничивает общую пропускную способность транзакций из-за перегрузки в пуле соединений с базой данных. Чем дольше удерживается соединение, тем больше других одновременных запросов будут ждать, чтобы получить соединение из пула.
Таким образом, либо вы удерживаете соединение слишком долго, либо вы приобретаете / освобождаете несколько соединений для одного HTTP-запроса, тем самым оказывая давление на базовый пул соединений и ограничивая масштабируемость.
Весенний ботинок
К сожалению, в Spring Boot по умолчанию включен Open Session in View .
Итак, убедитесь, что в application.properties
файле конфигурации у вас есть следующая запись:
spring.jpa.open-in-view=false
Это отключит OSIV, чтобы вы могли справиться LazyInitializationException
правильно .