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

Почему бы не использовать Spring OpenEntityManagerInViewFilter

В то время как много сообщений было написано на тему Spring OpenSession/EntityManagerInViewFilter, я не мог найти ничего, что упоминает его недостатки. Из того, что я понимаю, и принимая типичную многоуровневую архитектуру веб-приложений, используя сервисный уровень @Transactional, фильтр работает следующим образом:

  • Фильтр перехватывает запрос сервлета
  • Фильтр открывает EntityManager и связывает его с текущим потоком
  • Веб-контроллер называется
  • Веб-контроллер вызывает службу
  • Перехватчик транзакций начинает новую транзакцию, извлекает связанный с потоком EntityManager и связывает его с транзакцией
  • Вызывается служба, выполняет некоторые действия с EntityManager, а затем возвращает
  • Перехватчик транзакций сбрасывает EntityManager, затем совершает транзакцию
  • Веб-контроллер готовит представление, а затем возвращает
  • Вид построен
  • Фильтр закрывает EntityManager и отвязывает его от текущего потока

На шагах 8 и 9 все объекты, загруженные потоком EntityManager, все еще управляются. Следовательно, если на этих этапах затрагиваются ленивые ассоциации, они будут загружены из базы данных с использованием еще открытого EntityManager. Насколько я понимаю, каждый такой доступ требует, чтобы база данных открывала транзакцию. Spring управление транзакциями не будет знать об этом, поэтому я называю это "неявной транзакцией".

Я вижу две проблемы с этим:

  • Загрузка нескольких ленивых ассоциаций приведет к нескольким транзакциям с базами данных, возможному удару по производительности
  • Корневой объект и его ленивые ассоциации загружаются в разные транзакции базы данных, поэтому данные могут быть устаревшими (например, root загружен нитью 1, корневыми ассоциациями, обновленными потоком 2, корневыми ассоциациями, загруженными потоком 1)

С одной стороны, эти 2 проблемы кажутся достаточными, чтобы отклонить использование этого фильтра (поражение производительности, несогласованность данных). С другой стороны, это решение очень удобно, избегает написания нескольких строк кода, проблема 1 может быть не такой заметной, а проблема 2 может быть чистой паранойей.

Как вы думаете?

Спасибо!

4b9b3361

Ответ 1

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

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

Да, переход к БД часто может привести к проблемам с производительностью. В идеале вы хотите получить все данные, которые вам нужны в одной поездке. Подумайте об использовании Hibernate join-fetch для этого. Но получение слишком большого количества данных из БД также будет медленным. Эмпирическое правило, которое я использую, заключается в том, чтобы использовать извлечение соединения, если данные необходимы каждый раз, когда я рисую представление; если данные не нужны в большинстве случаев, я позволяю Hibernate ленивым извлекать его, когда мне это нужно, - тогда открывается секция openlocal open.

2) Корневой объект и его ленивые ассоциации загружаются в разные транзакции базы данных, поэтому данные могут быть устаревшими (например, root загружен потоком 1, корневыми ассоциациями, обновленными потоком 2, корневыми ассоциациями, загруженными потоком 1).

Представьте, что вы пишете это приложение в JDBC - если требования к согласованности приложений требуют, чтобы корневой каталог и оба они были загружены в один и тот же txn, используйте команду join. Если нет, то это часто случается, ленивая выборка не приведет к проблемам с согласованностью.

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

Ответ 2

Основной аргумент, который я слышал против OpenSessionInView и ленивая загрузка, - это избыток транзакций и негативное влияние на производительность. Это чрезвычайно удобно использовать в приложении с низкими требованиями к использованию, но в высокопроизводительном приложении я бы рекомендовал использовать старомодные полностью заполненные DTO (объекты передачи данных).

Ответ 3

Одной из основных проблем, с которыми я сталкиваюсь с OpenSessionInViewFilter, является использование приложений AJAX и javascript. Если вы используете javascript для рендеринга сеток или некоторых компонентов пользовательского интерфейса; есть ленивая нагрузка (если вы включите фильтр); и возникает исключение. В вашем представлении пользовательского интерфейса отображается бросок. Данные могут никогда не отображаться, страница начинает бросать странные исключения javascript, для которых вам нужно написать дополнительный код js для обработки. И вы подвергаете исключениям db пользователям (не очень хорошая идея).

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

Ответ 4

Если ваше приложение представляет собой многоуровневую архитектуру (уровень представления, развернутый на разных JVM и уровне обслуживания, будет развернут на разных виртуальных машинах), то сохранение сеанса в открытом состоянии не имеет смысла. Я бы не использовал OpenSessionViewFilter, если ваш уровень сервиса не зависит от вашего уровня приложения.