我在生產中部署了一個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 Session中分離出來,因爲這個流程全部發生在同一個請求中。最重要的是,這是一個非常隨機的問題 - 發生請求的時間可能只有1%,如果不是這樣的話。
爲了澄清,問題是;爲什麼會話是關閉的,以及爲什麼當對象在同一個請求範圍內發生時,對象會從Hibernate Session中分離出來?另外,爲什麼它只發生很少和隨機?
在嘗試訪問'account.transactions'之前,您是否嘗試過使用'account.attach()'?請參閱http://docs.grails.org/latest/ref/Domain%20Classes/attach.html –
嘿 - 我沒有特別嘗試過,但我會想像它會像「Account account = Account」一樣工作。 findById(session.account.id)'。我的問題不在於如何重新將域添加到會話中,因爲這很容易,但是爲什麼它首先被分離。您提供的鏈接中的文檔狀態如下: 「如果從會話中檢索到對象並將其放入Web範圍(如HttpSession),則會在Session關閉並丟棄時從Hibernate Session」分離「。 那麼,如果請求尚未完成,爲什麼會話關閉並丟棄? – DeaIss
Grails有一個Slack頻道,大師們傾向於閒逛。 StackOverflow更適合「如何...」的問題,所以我認爲您在Slack或Grails郵件列表中會有更好的成功。 –