2016-12-06 2 views
1

У меня есть приложение Grails (2.5.4), развернутое на производстве, которое получает большой объем трафика.Объект домена, хранящийся в сеансе, становится отсоединенным

При попытке доступа к полям из объектов домена, хранящихся в сеансе, мы получаем прерывистые исключения LazyInitializationException.

Чтобы уточнить, как работает поток:

У нас есть фильтр (http://docs.grails.org/2.5.4/ref/Plug-ins/filters.html), который вызывается перед каждым действием контроллера. В этом фильтре мы храним объект домена в сессии (http://docs.grails.org/2.5.4/ref/Servlet%20API/session.html), как это:

session.account = Account.get(1)

В контроллере мы отыскиваем домен, как это:

def account = session.account

Затем мы проходим domain object к другой службе, которая вызывает другую службу, которая в конечном итоге пытается вызвать поле hasMany на объекте домена следующим образом:

account.transactions.name

выше бросает LazyInitializationException с сообщением, похожим на это:

failed to lazily initialize a collection of role: com.example.app.Account.transactions, no session or session was closed

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

Мы обнаружили, выполнив следующие действия в контроллере полностью устраняет ошибку от происходящий:

Account account = Account.findById(session.account.id)

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

Чтобы уточнить, вопрос в том, Почему закрытие сеанса и почему объект отделен от сеанса Hibernate, когда все это происходит в пределах одного и того же запроса? Кроме того, почему это происходит очень редко и беспорядочно?

+0

Вы пытались использовать 'account.attach()' перед попыткой доступа к 'account.transactions'? См. Http://docs.grails.org/latest/ref/Domain%20Classes/attach.html –

+0

Эй. Я специально не пробовал это, но хотел бы, чтобы он работал так же хорошо, как и 'Account account = Account. findById (session.account.id) '. Мой вопрос заключается не в том, как повторно присоединить домен к сеансу, поскольку это легко, но почему его отделяют в первую очередь.Документация в указанной вами ссылке: «Если объект извлекается из сеанса и помещается в веб-область, например HttpSession, он будет« отсоединен »от сеанса Hibernate после закрытия сеанса и отбрасывается». Итак, почему сессия закрыта и отбрасывается, если запрос еще не закончен? – DeaIss

+0

У Grails есть канал Slack, где гуру склонны болтаться. StackOverflow лучше подходит для вопросов «Как ...», поэтому я думаю, что у вас будет лучший успех в Slack или в списке рассылки Grails. –

ответ

0

Привет, это происходит из-за того, что ленивый режим будет кэшировать только первый уровень домена, поэтому, когда вы попытаетесь получить доступ к другому полю, вы получите эту ошибку, и режим выборки по умолчанию обычно ленив, я буду придерживаться такого и делать то, что вы делаете, Учетная запись account = Account.findById (session.account.id)

Потому что в зависимости от размера списка на другой стороне, помещающего все в сеанс, не будет хорошо для вашей системы вообще ,

+0

Я понимаю, что домен использует ленивую загрузку, но если сеанс Hibernate все еще открыт, он должен иметь возможность получать любые отношения более высокого уровня в домене. Поэтому возникает вопрос: почему сеанс hibernate случайно закрывается и почему объект домена становится отсоединенным, когда запрос еще не закончился? – DeaIss