2014-01-24 2 views
4

Какое оптимальное решение для обработки ленивых загружаемых объектов в приложении Spring MVC? Я уже сделал несколько поисков по этой теме, и я нашел следующие решения:Lazy load handling (Hibernate + Spring MVC)

Открыть сеанс в поле зрения: открыть сеанс для каждого запроса и закрыть его после просмотра рендеринга. Проблема с этим решением заключается в том, что мне нужны ленивые объекты загрузки также вне модели Spring MVC (например, пример Junit). Другая обсуждаемая проблема с этим решением - обработка исключений. Что делать, если транзакция генерирует исключение во время рендеринга представления?

Открыть сеанс явно: открыть сеанс явно всякий раз, когда мне нужна ленивая загрузка объекта. На самом деле это решение должно работать, но я не думаю, что это правильный путь.

Использование АОП: создает аспект, который обертывает ленивый метод загрузки в сеансе. Это может быть решение, но я не знаю, на каком уровне моего приложения я должен определить poitcuts

Создание пользовательских запросов: создавать запросы для ленивой загрузки и запросов для активной загрузки. Это решение действительно работает, но мне кажется неправильным применением ленивого шаблона загрузки

+0

проверить это сообщение на OSIV-плюсах/минусах http://blog.jhades.org/open-session-in-view-pattern-pros-and-cons/ –

+0

Проблема с использованием пользовательских запросов заключается в том, что они принудительно присоединяют на связанный объект, что не всегда является оптимальным решением. Иногда его более эффективно иметь 1 запрос для основного объекта и N отдельных запросов для связанных объектов. – Solubris

+0

Кроме того, приятно отделить запрос от ленивой загрузки, так как это означает, что у вас может быть один метод для ленивой загрузки (например: loadRelationsRequiredByDefault()), который может быть повторно использован многими различными запросами, возвращающими один и тот же объект (или список объекты). – Solubris

ответ

2

Нет решения, которое всегда лучше во всех случаях, проблема в том, что @Transactional на уровне обслуживания не будет закрывать сессию при начале фазы рендеринга.

Сессия размыта, транзакция завершена и сеанс закрыт до начала рендеринга.

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

Другим способом является использование открытого сеанса в представлении, который удерживает сеанс открытым во время рендеринга, но это может привести к возникновению проблем N + 1 в приложении из-за непреднамеренного использования ленивой загрузки.

Также открытый сеанс связи может вызвать проблемы с не повторяемыми считываниями, когда некоторые данные были прочитаны уровнем обслуживания и использованы для фиксации транзакции, но когда рендеринг представления начинает, что данные больше не доступны или были изменены, и это важно для построения представления.

См. Это post от команды JBoss Seam по использованию OSIV, которая проходит через эти проблемы (Seam был разработан моими многими из тех же разработчиков, что и Hibernate).

Различные подходы имеют разные плюсы и минусы, в зависимости от приоритетов проекта. Если удобство не писать собственные запросы является значительным, так как есть много запросов для написания, то OSIV - хороший выбор. Вопросы Ocasional N + 1 можно решать в каждом конкретном случае и жить.

Если акцент делается на поддержании запросов под контролем, потому что приложение, например, критично для производительности, тогда пользовательские запросы являются опцией.

На самом деле нет четкого лучшего решения. Если вы используете технологию представления, которая работает на стороне клиента (что-то вроде angular.js) вместо сервера, тогда вы не сталкиваетесь с такими проблемами, потому что в ней нет поддержки стороны сервера.

0

Я не уверен, что это соответствует вашим требованиям, а не если это «правильный» способ обработки, но я использую @ Транзакционная аннотация. Таким образом, у меня было бы:

@Autowired 
AccountDAO accountDAO; 

@Transactional 
public List<String> getNamesOfAccount(String accountName){ 
    Account account = accountDAO.get(accountName); 
    return account.getNames(); 
} 

Атрибут имен в Аккаунте ленив и загружен непосредственно перед возвратом. Если есть лучший способ, дайте послушать!

+0

Это может быть решение. Я не знаю, лучший ли это. Я буду ждать других предложений. – JJJ

+0

Что хорошего в этом решении, так это то, что у вас есть только EntityManager/SessionFactory в вашем DAO. Если вы не вызываете getNames(), то ничего не загружается. Если вы делаете, чем Spring делает все для вас, и вам не нужно открывать сеанс или что-то в этом роде. –

+0

Меня не убеждает в том, что я не могу получить «ленивые поля» через интерфейс доменных объектов, но только через DAO. – JJJ