Issue
I have the following code:
The User
is a Hibernate domain.
for(User user : users) {
try {
function()
//log the user content
} catch(Exception ex) {
log.warn("Exception " + ex.toString() + ". Continue...")
}
}
Some fields of User
are beeing lazy loaded. And in a cases when function()
throws exception the lazy loading is throwing no Session
exception and accordingly the user content logging is broken.
While
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...")
}
}
works fine. I really need to understand the root cause of this so any hint is appreciated.
Solution
It's hard to say exactly what is going on, but probably at some point an exception is being thrown, which clears the Hibernate session, and the next time a proxy is accessed it throws the LazyInitializationException
.
see e.g. 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 mentions that
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.
I assume this is what happens in your case as well. I'm not sure why it does not occur in the second code snipped you posted, maybe the users.get(i)
code actually fetches the object again from your db.
Other Workarounds include:
- rework your code so no exception is thrown and the session is preserved
- use a separate session for each object (
User.withNewSession { ... }
) -> bad for performance - re-fetch objects after an exception occurs (also not optimal if you have to do it too often)
Answered By - Onno Rouast
Answer Checked By - David Marino (JavaFixing Volunteer)