如何使用传播等待事务提交 REQUIRES_NEW

How to wait for transactions to commit using Propagation REQUIRES_NEW

我想集成测试调用使用 @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
}

您遇到过自我调用。看这里:Spring - @Transactional - What happens in background? or Spring @Transactional Annotation : Self Invocation

这是我的一篇 类 的摘录:

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

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

我将这个私有成员用于带有@Cached 注释的自调用方法。

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

但是您的测试失败了,因为您正在使用 new 创建服务。 始终 在集成测试中使用依赖注入,这样您就可以获得配置好的 Spring bean,而不仅仅是一个新的未初始化的 POGO。为此,请在测试之外添加相同的 属性 语法:

def myService
def myService2

并删除 Spring 为您完成的不必要的接线代码(例如 myService.myService2 = myService2)。