我在生产中部署了一个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会话分离?另外,为什么它只是很少和随机发生?
答案 0 :(得分:0)
你好这是因为懒惰模式只会缓存域的第一级,所以当你尝试访问其他字段会给你这个错误而默认的提取模式通常是懒惰的,我会像这样保持这样做就像你在做的那样 帐户帐户= Account.findById(session.account.id)
因为根据另一方列表的大小,将所有内容放入会话中对您的系统来说根本不会有好处。