2009-10-08 2 views
35

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

  1. Фильтр перехватывает запрос сервлета
  2. Фильтр открывает EntityManager и связывает его с текущий поток
  3. Web контроллер называется
  4. Web-контроллер вызывает сервис
  5. Transaction перехватчик начинает новую транзакцию, извлекает нить переплете EntityManager и связывает его к сделке
  6. служба называется, делает некоторые вещи с EntityManager, затем возвращает
  7. транзакции перехватчика сбрасывается в EntityManager затем совершает сделку
  8. Web контроллер готовит представление, а затем возвращает
  9. View построен
  10. Фильтр закрывает EntityManager и отсоединяет его от текущей резьбы

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

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

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

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

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

Спасибо!

ответ

9

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

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

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

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

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

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

4

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

4

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

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

1

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

Смежные вопросы