【问题标题】:How to wait for transactions to commit using Propagation REQUIRES_NEW如何使用传播 REQUIRES_NEW 等待事务提交
【发布时间】:2015-04-21 12:14:27
【问题描述】:

我想集成测试一个调用使用@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 grails transactions


    【解决方案1】:

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

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

    def myService
    def myService2
    

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

    【讨论】:

    • 谢谢伯特,非常感谢。
    【解决方案2】:

    你已经面临自我调用。看这里: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 注释的自调用方法。

    【讨论】:

    • 谢谢 - 我已经修改了代码以将方法分成 2 个类,但似乎仍然无法正常工作,见上文。
    猜你喜欢
    • 2014-04-16
    • 2020-10-20
    • 1970-01-01
    • 2012-09-25
    • 2013-04-11
    • 2012-09-05
    • 2023-03-03
    • 1970-01-01
    • 2020-10-21
    相关资源
    最近更新 更多