grails withTransaction - 为什么它在域对象上?
grails withTransaction - why is it on a domain object?
我们需要能够回滚服务中的复杂事务,而不向调用方抛出异常。我的理解是,实现这一点的唯一方法是使用 withTransaction。
问题是:
- 为什么我必须在域对象上调用它,例如 Books.withTransaction
- 如果没有相关领域对象怎么办,随便挑一个会有什么后果?
下面或多或少是我正在尝试做的事情。用例是从帐户中提取并将其存入信用卡。如果转账失败,我们要回滚交易,而不是回滚支付记录日志,这必须在单独的交易中提交(使用 RequiresNew)。无论如何,服务方法必须return一个复杂的对象,而不是异常。
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
}
}
}
以上是有缺陷的 - 我假设 "return ob3" 不会从方法中 return ob3,因为它在闭包中。不确定如何从闭包内部到外部进行通信。
关于您的主要问题:您可以根据需要选择一个随机域对象,它不会造成任何伤害。或者,如果您愿意,您可以找到当前会话并在该会话上打开一个事务:
grailsApplication.sessionFactory.currentSession.withTransaction { /* Do the things */ }
在风格上我对这里没有偏好。其他人可能会。
Not sure how to communicate from inside a closure to outside it.
总的来说这可能很难; withTransaction
原则上可以 return 任何它想要的东西,不管它的闭包参数 return 是什么。但事实证明,withTransaction
return 的值是 return 由它的闭包编辑的。在这里,观看:
groovy> println(MyDomainObject.withTransaction { 2 + 2 })
4
按照惯例,所有采用闭包的 withFoo
方法都应该以这种方式工作,这样您就可以做您想做的事情。
我假设这个问题来自 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
。
我们需要能够回滚服务中的复杂事务,而不向调用方抛出异常。我的理解是,实现这一点的唯一方法是使用 withTransaction。
问题是:
- 为什么我必须在域对象上调用它,例如 Books.withTransaction
- 如果没有相关领域对象怎么办,随便挑一个会有什么后果?
下面或多或少是我正在尝试做的事情。用例是从帐户中提取并将其存入信用卡。如果转账失败,我们要回滚交易,而不是回滚支付记录日志,这必须在单独的交易中提交(使用 RequiresNew)。无论如何,服务方法必须return一个复杂的对象,而不是异常。
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
}
}
}
以上是有缺陷的 - 我假设 "return ob3" 不会从方法中 return ob3,因为它在闭包中。不确定如何从闭包内部到外部进行通信。
关于您的主要问题:您可以根据需要选择一个随机域对象,它不会造成任何伤害。或者,如果您愿意,您可以找到当前会话并在该会话上打开一个事务:
grailsApplication.sessionFactory.currentSession.withTransaction { /* Do the things */ }
在风格上我对这里没有偏好。其他人可能会。
Not sure how to communicate from inside a closure to outside it.
总的来说这可能很难; withTransaction
原则上可以 return 任何它想要的东西,不管它的闭包参数 return 是什么。但事实证明,withTransaction
return 的值是 return 由它的闭包编辑的。在这里,观看:
groovy> println(MyDomainObject.withTransaction { 2 + 2 })
4
按照惯例,所有采用闭包的 withFoo
方法都应该以这种方式工作,这样您就可以做您想做的事情。
我假设这个问题来自 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
。