内部有 try/catch 的 foreach 循环中的延迟加载异常

Lazy Load Exception in a foreach loop with try/catch inside

我有以下代码: User 是一个 Hibernate 域。

for(User user : users) {
            try {
                function()
                //log the user content 
            } catch(Exception ex) {
                log.warn("Exception " + ex.toString() + ". Continue...")
            }
}

User 的某些字段正在延迟加载。在 function() 抛出异常的情况下,延迟加载会抛出 no Session 异常,因此用户内容记录被破坏。 而

for(int i=0; i<users.size();++i) {
            var user = users.get(i)
            try {
                function()
                //log the user content 
            } catch(Exception ex) {
                log.warn("Exception " + ex.toString() + ". Continue...")
            }
}

工作正常。 我真的需要了解这的根本原因,所以任何提示都将不胜感激。

很难说到底发生了什么,但可能在某个时候抛出异常,这会清除 Hibernate 会话,并且下次访问代理时它会抛出 LazyInitializationException

参见例如https://docs.grails.org/5.1.7/guide/single.html#declarativeTransactions

[Transactional] methods are wrapped in a transaction and automatic rollback occurs if a method throws an exception (both Checked or Runtime exceptions)

https://docs.grails.org/5.1.7/guide/single.html#transactionsRollbackAndTheSession 提到

When a transaction is rolled back the Hibernate session used by GORM is cleared. This means any objects within the session become detached and accessing uninitialized lazy-loaded collections will lead to a LazyInitializationException.

我想这也是您的情况。我不确定为什么它不会出现在您发布的第二个代码片段中,也许 users.get(i) 代码实际上再次从您的数据库中获取对象。

其他解决方法包括:

  • 重写您的代码,以便不抛出异常并保留会话
  • 为每个对象使用单独的会话 (User.withNewSession { ... }) -> 不利于性能
  • re-fetch 异常发生后的对象(如果你必须经常这样做也不是最佳的)