一般动作
问题代码:
抛出异常:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
bropen.framework.core.security.Domain.applications, no session or session was closed
... 13 more
在错误日志上加上 withTransaction 或者 withNewSession 都不管用,该如何处理呢?
其原因在于,bropen.framework.core.security.Domain.current()(包括DomainApplication.current())拿到的实体Bean都是来自缓存,而这些缓存可能是早在被其他代码(比如BootStrap)调用时生成的,当时的Hibernate Session早已关闭,如果通过这些Bean去获得关联的其他实体对象,肯定会抛出no session or session was closed异常。
知道原因后,解决问题就很容易了,可以采用两种方式来处理:
1. 通过获得实体对象后,调用 attach 方法将对象附加到当前的Hibernate Session中,代码如:
这种处理方式适用与多数类似的异常,但是如果这个bean可能同时被多个线程调用,这样做会不会导致线程不安全的情况发生呢(细心的读者可以验证一下)。
因此,比较偷懒的做法是采用下面的方案2来规避这个问题。
2. 接受这个bean游离在当前Hibernate Session之外的现实,通过其他手段来获取关联的其他实体对象,就最上面的问题代码来说,改造如下:
当然,为什么不把关联的 applications 也缓存下来呢?
呵呵,那缓存的工作量就比较大了,整个系统的数据结构都有可能相互关联,谁也无法预料到二次开发时中会如何调用,这样做意义并不大;而且,如果关联的对象发生了变化,还得通知缓存进行更新......
类似的,如果碰到类似的异常,也可以采用相同的方法处理。