我们需要能够回滚服务中的复杂事务,而不会向调用者抛出异常。我的理解是,实现这一目标的唯一方法是使用withTransaction。
问题是:
下面或多或少是我想要做的。用例是从帐户中提取并将其放入信用卡。如果传输失败,我们想要回滚事务,而不是支付记录日志,这必须在单独的事务中提交(使用RequiresNew)。无论如何,服务方法必须返回一个复杂的对象,而不是异常。
someService.groovy
Class SomeService {
@NotTransactional
SomeComplexObject someMethod() {
SomeDomainObject.withTransaction{ status ->
DomainObject ob1 = new DomainObject.save()
LogDomainObject ob2 = insertAndCommitLogInNewTransaction()
SomeComplexObject ob3 = someAction()
if (!ob3.worked) {
status.setRollbackOnly() // only rollback ob1, not ob2!
}
return ob3
}
}
}
以上是有缺陷的 - 我假设"返回ob3"不会从方法中返回ob3,因为它在闭包中。不确定如何从封闭内部到外部进行通信。
答案 0 :(得分:7)
对于您的主要问题:如果您愿意,可以选择一个随机域对象,它不会造成任何伤害。或者,如果您愿意,可以找到当前会话并在其上打开一个事务:
grailsApplication.sessionFactory.currentSession.withTransaction { /* Do the things */ }
从文体上来说,我没有偏好。其他人可能。
不确定如何从闭包内部到外部进行通信。
总的来说,这可能很难; withTransaction
原则上可以返回它想要的任何内容,无论它的闭包参数返回什么。但事实证明withTransaction
返回其闭包返回的值。在这里,观看:
groovy> println(MyDomainObject.withTransaction { 2 + 2 })
4
按照惯例,所有采用闭包的withFoo
方法都应该以这种方式工作,这样才能完成你想要做的事情。
答案 1 :(得分:1)
我假设这个问题来自grails 2应用程序,而2015年以来的问题现在已经修复。
我在grails 2的任何文档中都找不到,但是服务在其方法中注入了一个神奇的transactionStatus
变量。 (至少在grails 2.3.11中)
您可以仅保留所有注释并使用该注入的变量。
Class SomeService {
SomeComplexObject someMethod() {
DomainObject ob1 = new DomainObject.save()
LogDomainObject ob2 = insertAndCommitLogInNewTransaction()
SomeComplexObject ob3 = someAction()
if (!ob3.worked) {
transactionStatus.setRollbackOnly() // transactionStatus is magically injected.
}
return ob3
}
}
此功能在grails 2中,但未记录。在grails 3中有记录。 https://docs.grails.org/latest/guide/services.html#declarativeTransactions
搜索transactionStatus
。