如何使用Propagation REQUIRES_NEW等待事务提交

时间:2015-04-21 12:14:28

标签: spring grails transactions

我想集成测试一个调用使用@Transactional(propagation = Propagation.REQUIRES_NEW)的方法的服务方法。但是,基于内部(新)事务的断言失败。

class MyService {

    @Transactional(propagation = Propagation.NESTED)
    def method1() {
        method2()
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    def method2() {
        // some code that will modify the DB
    }
} 

class MyServiceNonTransactionalIntegrationSpec extends IntegrationSpec {
    static transactional = false

    def myService = new MyService()

    setup() {
        // populate database here
    }

    cleanup() {
        // teardown database here after tests complete
    }

    def method1() {
        when: "we test the main method"
            myService.method1()

        then: "we should be able to see the result of method 1 and method 2"
           // BUT: (!!!)
           // assertions based on state of database fail, perhaps because new transaction
           // wrapped around method 2 has not yet committed
    }
}

如何集成测试method1()

编辑:

为了解决代理问题,我尝试了以下方法,但仍然无法让它工作:

class MyService {

    def myService2

    @Transactional(propagation = Propagation.NESTED)
    def method1() {
        myService2.method2()
    }    
} 

class MyService2 {

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    def method2() {
        // some code that will modify the DB
    }
} 

class MyServiceNonTransactionalIntegrationSpec extends IntegrationSpec {
    static transactional = false

    def myService = new MyService()
    def myService2 = new MyService2()

    setup() {
        myService.myService2 = myService2
        // populate database here
    }

    // rest as before
}

2 个答案:

答案 0 :(得分:1)

如果您正在使用org.springframework.transaction.annotation.Transactional,这只是一个自我调用的问题 - 您应该使用@grails.transaction.Transactional而不是具有相同的配置选项但使用AST转换而不是运行时代理来避免问题不调用代理方法。使用Grails注释时,会重写每个方法以模拟为每个方法创建代理,将代码包装在基于该方法的注释设置配置的事务模板中(在方法上显式,或从类范围注释推断) )。

但您的测试已被破坏,因为您正在使用new来创建服务。 始终在集成测试中使用依赖注入,因此您可以获得已配置的Spring bean,而不仅仅是新的未初始化的POGO。为此,请添加与测试之外相同的属性语法:

def myService
def myService2

并删除Spring为您执行的不必要的布线代码(例如myService.myService2 = myService2)。

答案 1 :(得分:0)

你面临着自我调用。点击此处:Spring - @Transactional - What happens in background?Spring @Transactional Annotation : Self Invocation

以下是我的一个课程的摘录:

@Service("authzService")
public class AuthorizationService implements IAuthorizationService {

    @Resource(name="authzService")
    private IAuthorizationService self;

我使用这个私有成员来自行调用带有@Cached注释的方法。

相关问题