Воспользовавшись ленивой загрузкой Hibernate? - PullRequest
0 голосов
/ 20 февраля 2010

У меня есть объект домена, у которого есть атрибут, представляющий собой коллекцию, содержащую другой объект домена. Это достигается с помощью отображения гибернации (которое в конечном итоге выполняет соединение с другой таблицей). Hibernate, по умолчанию, кажется, лениво создает экземпляр этой коллекции. Это оказывается отличной вещью, потому что, в зависимости от того, что мне нужно отобразить, мне не всегда нужно загружать коллекцию.

Моя проблема заключается в следующем: при написании моих запросов гибернации (в моих DAO) я использую следующее для открытия / закрытия сеанса:

Session session = getSessionFactory().openSession();
//query goes here using the session var
session.close();

Проблема в том, что когда Hibernate наконец-то начинает лениво загружать мою коллекцию, Session уже давно закрыт! Как я могу обойти это? Я предполагаю, что я должен закрыть сессию, как я делаю ...

Это ошибка, которую я получаю:

SEVERE: failed to lazily initialize a collection of ...

Ответы [ 2 ]

5 голосов
/ 20 февраля 2010

Если это происходит в веб-приложении, то легко исправить это с помощью OpenSessionInViewInterceptor или OpenSessionInViewFilter . Они задерживают закрытие сеанса до завершения всего запроса, позволяя вам перемещаться по ленивым ассоциациям при рендеринге представления.

Более общее решение состоит в том, чтобы переписать ваши запросы так, чтобы они явно указывали, какие ассоциации следует извлекать заранее. Это позволяет вам по умолчанию хранить ассоциации ленивыми и в то же время обслуживать особые случаи, когда вы хотите, чтобы они извлекались с нетерпением. См. Описание "fetch joins" в документах Hibernate.

Соединение "fetch" позволяет связывать или коллекции значений, которые будут инициализируется вместе с их родителем объекты с помощью одного выбора. Это особенно полезно в случае коллекция. Это эффективно переопределяет внешнее соединение и ленивые объявления файла сопоставления для ассоциаций и коллекции

2 голосов
/ 20 февраля 2010

Я понимаю, что вы открываете и закрываете сеанс для каждой операции DAO. Вместо этого вы можете использовать один и тот же сеанс всеми DAO, открытыми когда-то во время инициализации и закрытыми при завершении работы. Обратите внимание, что Hibernate Reference упоминает "сеанс на операцию" как антипаттерн:

"Не используйте антипаттерн сеанса для каждой операции: не открывайте и не закрывайте сеанс для каждого простого вызова базы данных в одном потоке."

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

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

...