grails withTransaction - 为什么它在域对象上?

时间:2015-05-04 14:55:38

标签: grails rollback

我们需要能够回滚服务中的复杂事务,而不会向调用者抛出异常。我的理解是,实现这一目标的唯一方法是使用withTransaction。

问题是:

  1. 为什么我必须在域对象上调用它,例如Books.withTransaction
  2. 如果没有相关的域对象,选择一个随机的后果是什么?
  3. 下面或多或少是我想要做的。用例是从帐户中提取并将其放入信用卡。如果传输失败,我们想要回滚事务,而不是支付记录日志,这必须在单独的事务中提交(使用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,因为它在闭包中。不确定如何从封闭内部到外部进行通信。

2 个答案:

答案 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