My Grails app has a a service method that updates a list of artists from last.fm's web service.
@Transactional(propagation = Propagation.NOT_SUPPORTED)
void updateLastFmArtists(Range idRange = null) {
Artist.list().each { Artist artist ->
// We could be updating a lot of artists here, the process could take up
// to an hour and we don't want to wrap all that in a single transaction
Artist.withTransaction { status ->
try {
updateArtistInfo(artist)
} catch (IOException ex) {
status.setRollbackOnly()
}
}
}
}
Each individual artist is updated within it's own transaction, which should be rolled back if an IOException is thrown. However, I noticed the following behaviour:
If an attempt to update an artist throws an IOException - causing the transaction to be rolled back - then the update of the next artist always fails due to the following error
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.example.Artist.topTracks, no session or session was closed
If I change the code above so that each artist is updated within it's own session, this seems to fix the problem,
Artist.withNewSession { session ->
Artist.withTransaction { status ->
try {
updateArtistInfo(artist)
} catch (IOException ex) {
status.setRollbackOnly()
}
}
}
But I don't understand why I need to do this, i.e. why is that rolling back a transaction seems to close the session?