Объект домена, хранящийся в сеансе, становится отсоединенным

У меня есть приложение 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

Затем мы передаем объект домена другой службе, которая вызывает другую службу, которая в конечном итоге пытается вызвать поле 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, когда все это происходит в одной области запроса? Кроме того, почему это происходит очень редко и случайным образом?


person DeaIss    schedule 06.12.2016    source источник
comment
Пробовали ли вы использовать account.attach() перед попыткой доступа к account.transactions? См. docs.grails.org/latest/ref/Domain%20Classes/attach. .html   -  person Emmanuel Rosa    schedule 08.12.2016
comment
Эй, я специально не пробовал, но думаю, что это сработает так же хорошо, как и Account account = Account.findById(session.account.id). Мой вопрос не в том, как повторно подключить домен к сеансу, поскольку это легко, а в том, почему он вообще отключается. Документация в указанной вами ссылке гласит: если объект извлекается из сеанса и помещается в веб-область, такую ​​​​как HttpSession, он будет отсоединен от сеанса Hibernate после закрытия сеанса и его удаления. Так почему же сеанс закрывается и отбрасывается, если запрос не завершен?   -  person DeaIss    schedule 08.12.2016
comment
У Grails есть канал Slack, где обычно тусуются гуру. StackOverflow лучше подходит для вопросов «Как…», поэтому я думаю, что вы добьетесь большего успеха в Slack или в списке рассылки Grails.   -  person Emmanuel Rosa    schedule 09.12.2016
comment
Спасибо - я спросил на слабом канале. Я отчитаюсь, если получу ответ.   -  person DeaIss    schedule 09.12.2016


Ответы (1)


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

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

person Galeixo    schedule 06.12.2016
comment
Я понимаю, что домен использует ленивую загрузку, но если сеанс гибернации все еще открыт, он должен иметь возможность получать любые отношения домена более высокого уровня. Итак, вопрос в том, почему сеанс гибернации случайно закрывается и почему объект домена становится отсоединенным, когда запрос не завершен? - person DeaIss; 06.12.2016