我有一个grails服务,它对给定的域对象执行操作。此操作可能会失败,如果是,我希望该操作的事务回滚。
我还有一个控制器,它遍历这个域类的所有实例,在每个实例上调用服务。如果给定对象的服务操作失败,我想继续处理其余的域对象,每个对象都在自己的独立事务中。
只是为了澄清,我需要一个房子内的所有房间(参见下面的域类)在一次交易中处理,但每个房子单独交易。
有没有办法实现这个目标?下面是我尝试过的,但是当我尝试在其中一个对象失败后的操作之后尝试处理后续对象时,我一直得到以下异常。可能是在回滚事务时Hibernate会话被关闭了吗?
(注意:切换到急切加载可能不适合我,因为我们的真实域类实际上包含多个hasMany关系。)
例外:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.blah.House.rooms, no session or session was closed
代码:
class DataService {
static transactional = true
def processStuff(House house){
house.rooms.each{
if(someCondition){
throw new RuntimeException('failed') // will cause txn to roll back
}
}
}
}
class DataController {
def dataService
def doSomething(){
def houses = House.findAll()
houses.each{ house ->
dataService.processStuff(house)
}
render(view:'someView')
}
}
class House {
def hasMany = [rooms: Room]
}
class Room {
}
答案 0 :(得分:1)
根问题是在回滚事务时清除Hibernate会话(从而使所有延迟加载的集合无效)。在Grails docs。
中记录了此行为(及其变通方法)就我而言,最好的解决方案是在每次交易开始时重新加载父对象;这将重新初始化延迟加载集合。
class DataService {
static transactional = true
def processStuff(House house){
house = House.get(house.id) // <-- reload to reinstate lazy collections
house.rooms.each{
if(someCondition){
throw new RuntimeException('failed') // will cause txn to roll back
}
}
}
}