【问题标题】:Grails do not commit after a successful service call服务调用成功后 Grails 不提交
【发布时间】:2016-01-15 08:39:45
【问题描述】:

我在 2.4.4 中的单个Service 上执行以下逻辑。

class SampleService {
    void process(params1, params2) {
        SampleDomain1 sd1 = new SampleDomain1()
        sd1.setProperties(params1)
        sd1.save()

        SampleDomain2 sd2 = new SampleDomain2()
        sd2.setProperties(params2)
        sd2.save()
    }
}

我的理解是Services 默认是事务性的。如果sd1.save() 成功但sd2.save() 不成功,它将回滚更改并抛出错误。而如果两者都成功,则两者都会在服务退出时提交。

如果我的理解是正确的,那么这两个应该都已经持久化到数据库中了。但是,问题是:它不会——除非您根据我使用同一组params1params2 的测试明确使用flush: true 参数。

        sd1.save(flush: true)

        SampleDomain2 sd2 = new SampleDomain2()
        sd2.setProperties(params2)
        sd2.save(flush: true)
    }

顺便说一句,这是我真正要避免的(将其设置为@Transactional 有什么意义)。如果这是 Hibernate 4 / Grails 2.4 的问题,我需要做什么才能让我的服务在每次服务调用结束时再次提交?我需要配置 Grails 的任何全局配置吗?我真的需要在每项服务结束时自动刷新我的域类。


注意

我已经确认数据是正确的,包括调用.validate() 和其他检查器。成功执行.save(flush: true) 证明了这一点。我发现的问题是regarding to the update on Grails 2.4 在其FlushMode 上。现在,也许我真正需要的是一个全局设置来覆盖它。

【问题讨论】:

  • 尝试将这个:grails.gorm.failOnError=true 添加到您的Config.groovy。这将告诉 Grails 在 GORM 持久性发生错误时全局抛出异常。
  • 此外,刷新 Hibernate 会话(即使您的数据库与内存中的对象保持同步)与提交事务不同。因此,即使在刷新之后,事务的回滚也会恢复数据库更改。此外,我发现执行assert domainObject.save() 是一个很好的做法,以确保正确保存对象。

标签: grails grails grails-orm transactional


【解决方案1】:

如果您的数据没有被刷新到数据库层,那么您会想到一些可能性。

  1. 尝试保存到数据库时出现某种错误,您可以尝试将 failOnError=true 参数传递给 .save() 调用以清楚地看到它。 (实际上全局设置是一个好主意,因为静默失败的数据库调用是一种偏头痛)

  2. 您正在从同一个服务对象中调用此服务方法。由于使用了代理,这将不允许底层的 Spring 声明式事务工作。

  3. 您可能在同一个服务中注释了一些其他方法,在这种情况下,默认事务支持不再适用于剩余的未注释(这甚至是一个词吗?)方法。

  4. 您可能在服务文件夹之外的某个位置创建了服务,但不太确定这是否会导致问题,因为我从未尝试过。

  5. 您未能将山羊献给 Groovy 和 Grails 之神,他们正在弄乱您的脑袋。

编辑: 我将尝试回答您新编辑中的要点。

  1. 您尝试过 failOnError 吗?当两个对象同时刷新到数据库而不是手动一次提交一个时,这可能是一个问题。

  2. 通过找出一种在保存时自动刷新的方法,您将完全绕过事务 AFAIK,现在如果我错了,那么一定要去做。但是在假设之前先测试一下。

【讨论】:

    【解决方案2】:

    在我的DataSource.groovy 配置的某处,有这一行:

    hibernate {
            ...
            singleSession = true // configure OSIV singleSession mode
            flush.mode = 'manual' // OSIV session flush mode outside of transactional context
            ^^^^^^^^^^
    }
    

    其中明确规定每次保存都应手动刷新。作为解决方案,我注释掉这一行。之后,每个数据库事务现在每次存在 Service 时都会提交。

    【讨论】:

      猜你喜欢
      • 2015-02-08
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-25
      • 1970-01-01
      相关资源
      最近更新 更多