【问题标题】:afterUpdate event hook, transactions, and old state in consecutive requestsafterUpdate 事件挂钩、事务和连续请求中的旧状态
【发布时间】:2016-11-24 17:06:16
【问题描述】:

我们遇到了一个奇怪的问题,即在第一个请求中创建了对象,但在第二个请求中没有返回它们。 假设我们有两个域类:

Class A {
    static hasMany = [bs: B]

    def afterUpdate() {
        this.addToBs(new B(a: this))
        this.save()
    }
}

Class B {
    static belongsTo = [a: A]
}

当通过 PUT /as/<id> 在 A 的实例上发送 put 时,update() 会在带有 @Transactional 注释的 RestfulController 中调用。

我们可以观察到,在第一个请求的响应返回后,API 使用者每隔一段时间发送一个后续请求,GET /bs 并没有返回 B 的新实例,这应该是在第一个请求中创建,并在后续请求中返回。

我希望 grails 仅在事务提交后才将响应发送给 API 使用者,这意味着下一个请求应该会看到该事务的所有更改,不是吗?

这种行为的原因可能是什么?在 grails 应用程序已经将响应发送给 API 使用者之后,事务是否已提交?如果是这样,@Transactional 周围的update() 是默认打开的原因吗?

我知道在这个例子中afterUpdate 中的代码可能也可以放入beforeUpdate,但我只是尽量简化这个例子。

【问题讨论】:

    标签: grails transactions grails-orm


    【解决方案1】:

    根据我的经验,afterUpdate() 等中的代码不包含在事务中。您必须明确地创建一个事务(也可能是一个会话)。见http://docs.grails.org/latest/ref/Domain%20Classes/withTransaction.html

    我建议不要在afterUpdate() 和朋友中进行 GORM 更新,因为它会导致类似这样的奇怪问题,并且难以对域模型进行单元测试。如果您将保存委托给事务服务,那么它不仅可以正常工作,而且您还可以通过集成测试来确认它。

    在我的 Grails 应用程序中,我的控制器真的很笨:

    1. 调用服务
    2. 返回服务的输出(可能对其进行格式化)。

    我将所有业务逻辑都保留在服务中,因为控制器很难测试好。这是一个例子:

    @grails.transaction.Transactional
    class SomeService {
        def saveA(A a) {
            // This method will run in a transaction.
            a.addToBs(new B(a: this))
            a.save()
        }
    }
    

    在控制器中...

    class SomeController {
        def update() {
            ...
            someService.save(a)
        }
    }
    

    【讨论】:

    • 感谢伊曼纽尔的建议。我想也许仍然可以正确使用这些钩子,但我会检查将操作放入服务中。
    • 您可以使用这些钩子,但您需要分别使用DomainClass.withSession()DomainClass.withTransaction() 在新会话或事务(我不记得是哪一个)中包装 GORM 使用.问题是钩子在@transaction 之外执行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 2013-04-01
    • 2011-03-01
    • 2016-09-22
    • 2011-12-25
    • 2018-02-14
    相关资源
    最近更新 更多