Почему бы не использовать Spring OpenEntityManagerInViewFilter - PullRequest
36 голосов
/ 08 октября 2009

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

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

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

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

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

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

Что вы думаете?

Спасибо!

Ответы [ 4 ]

9 голосов
/ 11 октября 2009

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

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

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

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

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

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

4 голосов
/ 12 мая 2010

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

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

4 голосов
/ 11 октября 2009

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

1 голос
/ 30 июня 2015

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

...