E.g。
@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()
}
}
答案 0 :(得分: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
}
}