Gre*_*egg 9 grails transactions exception
我有以下代码:
class ServiceA {
def save(Object object) {
if (somethingBadComesBack) {
throw new CustomRuntimeException(data)
}
}
}
class ServiceB {
def serviceA
def save(Object object) {
try {
serviceA.save(object)
// do more stuff if good to go
} catch(CustomRuntimeException e) {
// populate some objects with errors based on exception
}
}
}
class ServiceC {
def serviceB
def process(Object object) {
serviceB.save(object)
if (object.hasErrors() {
// do some stuff
}else{
// do some stuff
}
def info = someMethod(object)
return info
}
}
class SomeController {
def serviceC
def process() {
def object = .....
serviceC.save(object) // UnexpectedRollbackException is thrown here
}
}
Run Code Online (Sandbox Code Playgroud)
当ServiceA.save()调用并发生异常时,它会在尝试返回时ServiceC.save()抛出UnexpectedRollbackException.
我做了以下事情:
try {
serviceC.process(object)
}catch(UnexpectedRollbackException e) {
println e.getMostSpecificCause()
}
Run Code Online (Sandbox Code Playgroud)
我得到了:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
Run Code Online (Sandbox Code Playgroud)
我不知道从哪里开始寻找如何解决这个问题.
Bur*_*ith 11
您正在使用运行时异常来回滚事务,但这是作弊 - 它正在利用副作用.运行时异常会自动回滚事务,因为您不需要捕获它们,所以假设如果抛出一个,则不会预期,并且默认行为是回滚.您可以将方法配置为不针对特定的预期运行时异常进行回滚,但这种情况有点罕见.已检查的异常不会回滚异常,因为在Java中它们必须被捕获或声明throws,因此您必须明确地抛出它或将其删除; 无论哪种方式,你都有机会再试一次.
故意回滚事务的正确方法是调用setRollbackOnly()当前TransactionStatus但是这不能在服务方法中直接访问(它在withTransaction块中,因为它是闭包的参数).但它很容易到达:导入org.springframework.transaction.interceptor.TransactionAspectSupport和调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly().这将要求您重新编写代码,因为不会有异常捕获,因此您需要检查它是否已回滚TransactionAspectSupport.currentTransactionStatus().isRollbackOnly().
我不确定它是Grails问题还是标准行为,但是当我调试这个时,有3个提交调用有3个不同的TransactionStatus实例.只有第一个设置了回滚标志,但第二个意识到第一个并且没问题.第三个被认为是一个新的交易,并且引发了您所看到的同一个异常.所以为了解决这个问题,我将其添加到第二和第三种服务方法中:
def status = TransactionAspectSupport.currentTransactionStatus()
if (!status.isRollbackOnly()) status.setRollbackOnly()
Run Code Online (Sandbox Code Playgroud)
链接回滚标志.这工作,我没有得到UnexpectedRollbackException.
将此与已检查的异常相结合可能更容易.它仍然过于昂贵,因为它会不必要地填充堆栈跟踪,但是如果你调用setRollbackOnly()并抛出一个已检查的异常,你将能够使用你现在拥有的相同的通用工作流程.
| 归档时间: |
|
| 查看次数: |
4357 次 |
| 最近记录: |