【问题标题】:grails 2.4.4 : how to immediately commit each insert (aka save) in a service method.?grails 2.4.4:如何在服务方法中立即提交每个插入(又名保存)。?
【发布时间】:2015-03-02 17:06:13
【问题描述】:
  1. 如果我声明一个方法是非事务性的,那么我保存一条记录,做一些事情,保存另一条记录,即使第二次保存失败并抛出异常,第一次保存是否会提交,无论如何?李>
  2. 如果从另一个事务性服务方法调用 NonTransactional 服务方法,会发生什么?它现在是否成为外部事务的一部分,因此如果 SomeOtherdomainObject().save() 失败,第一个对象将被回滚?

例如

@Transactional
class SomeService {
    @NotTransactional
    def someMethod() {
        new SomeDomainObject().save(failOnError:true, flush:true)
        // do stuff, possibly throw a RuntimeException
        new SomeOtherdomainObject().save(failOnError:true)
        // do more stuff, possibly throw a RuntimeException
    }
}

如此调用(在非事务调用情况下):

class SomeControler{
   def someService
   def someControllerMethod() {
       someService.someMethod()
   }
}

【问题讨论】:

  • 由于您似乎有一个要测试的设置,我建议您将 Hibernate 日志记录设置为调试模式以查看会话和事务的工作情况。调试'org.hibernate'

标签: grails transactions commit


【解决方案1】:

据我所知:

  1. 是的。
  2. 是的。

为什么不设置一些集成测试来确认这一点(并让我们知道结果)?有a good guide here。请注意,为了测试事务功能,需要将测试类设置为非事务性的。我链接到的示例页面使用 JUnit,但这里有一些 Spock 代码应该可以满足您的需求。

// MyDomainObject.groovy
class MyDomainObject {
    String details

    static constraints = {
        // this is default anyway, but I want to make it obvious
        // not setting details and then calling save will cause an exception if
        // save's failOnError is true
        details nullable: false  
    }
}

// MyService.groovy
class MyService {
    // only make methods transactional when we explicitly want them to be
    static transactional = false

    // create 2 objects and save, 1st should save ok and second should fail
    def nonTransactionalDoubleSave() {
        def objA = new MyDomainObject()
        objA.details = "This should save ok"
        objA.save(flush: true, failOnError: true)

        def objB = new MyDomainObject()
        objB.details = null  // null by default, but I'm just making the point
        objB.save(flush: true, failOnError: true)  // this will trigger an exception
    }

    def nonTransactionalSingleSave() {
        def objA = new MyDomainObject()
        objA.details = "This should save ok"
        objA.save(flush: true, failOnError: true)
    }

    @Transactional
    def transactionalSave() {
        nonTransactionalSingleSave()  // this should create 1 object
        // this should create 2 objects, but the 2nd will trigger an exception and rollback the transaction, meaning there should be no objects in the DB
        nonTransactionalDoubleSave()  
    }
}


import spock.lang.*
import grails.test.spock.*

class MyServiceIntegrationSpec extends IntegrationSpec {    
    static transactional = false  // the test case must not be transactional

    def myService = new MyService()

    def setup() {
        // remove all my domain objects from the database that might be in there
        MyDomainObject.where{}.deleteAll()
    }

    def cleanup() {
        // remove all my domain objects from the database that a test may have created
        MyDomainObject.where{}.deleteAll()
    }

    def "Question 1: nonTransactionalDoubleSave should create 1 object only"() {
        expect: "a clean database"
        MyDomainObject.count() == 0

        when: "nonTransactionalDoubleSave is called"
        myService.nonTransactionalDoubleSave()

        then: "we get an exception but still get one object in the database"
        thrown(Exception)
        MyDomainObject.count() == 1
        def obj = MyDomainObject.list().getAt(0)
        obj.details = "This should save ok"
    }

    def "Question 2: transactionalSave should create no objects"() {
        expect: "a clean database"
        MyDomainObject.count() == 0

        when: "transactionalSave is called"
        myService.transactionalSave()

        then: "we get an exception and no objects in the database"
        thrown(Exception)
        MyDomainObject.count() == 0
    }

}

【讨论】:

  • 请注意,在您上面的代码中,有一个小“陷阱”。如果您将@Transactional 放在一个方法中,它会默默地忽略“static transactional = xxx”声明,即使您说“static transactional = true”,该类也会变为非事务性的。这让我很多次。在你的例子中,这并不重要,因为你说的是​​假的。
  • 谢谢,我不知道!
猜你喜欢
  • 2017-02-26
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
  • 2013-04-19
  • 2021-01-16
  • 2015-04-29
  • 2013-06-11
  • 1970-01-01
相关资源
最近更新 更多