Grails版本2.4.3
我的代码如下,当我在正在处理的方法中抛出运行时异常时,我可以继续并保存。但是,如果我在SecondLevelService中抛出运行时异常,则会出现错误
secondLevelService.TestA()它所做的一切
throw new RuntimeException('This is a Run time exception Second Level')
事务已回滚,因为它已被标记为仅回滚
因为错误表示它已回滚并且没有保存任何内容。
任何人都可以帮助我理解为什么差异,我希望它更接近方法中抛出的异常。通过关闭二级服务中的事务来处理错误,但这不符合我的要求。
class FirstLevelService {
SecondLevelService secondLevelService
def TestA() {
com.Author author = null
com.Book book = null
try {
//Create a database record
author = new com.Author(firstName:'TestXXX', lastName: 'User XXX' )
book = new com.Book(title: 'Test Book XXX', pageCount: 1 )
author.addToBooks(book)
println 'Book Save'
author.save(failOnError:true)
println 'Is Dirty 1st Save:' + author.isDirty()
println author.books?.size()
//Fail with Runtime exception this is do other things to the book and author
throw new RuntimeException('This is a Run time exception')
//secondLevelService.TestA()
}
catch (RuntimeException re) { //Cause I am catching any saving should be okay
println 'Exception caught'
println re.message
} finally {
//But make the change to author anyway
println 'Change the first Name'
author.firstName = 'TestYYY ' + new Date().toString()
println 'Is Dirty before Save:' + author.isDirty()
println 'Save Change the first Name: ' + author.firstName
if (!author.validate()) {
author.errors.each {
println it
}
}
println 'Is Dirty before 2nd Save:' + author.isDirty()
author.save(failOnError:true)
println 'Is Dirty:' + author.isDirty()
}
}
}
答案 0 :(得分:1)
基本上这正是预期的行为。在服务中引发并且未在同一服务中捕获的RuntimeException导致事务的回滚(请参阅grails service docs:12.1声明性事务)。
如果你想绕过它,你有不同的可能性。第一个是,此回滚行为仅适用于RuntimeExceptions或错误 - 不适用于已检查的异常。这是事实,尽管groovy对已检查的异常与未经检查的异常有一点不同的理解。文档在这里提出的观点是,Spring意识到了这一点,这就是原因。
我能想到的另一个可能的解决方案不是在两个服务中共享交易。这应该有效,因为默认的事务传播行为是PROPAGATION_REQUIRED。这意味着,如果第二个服务创建了运行时异常,则会在整个事务中调用transaction.setRollbackOnly()
。因此,您可以在第二个服务中要求新的交易,也可以根本不使用交易。