Spring Boot 强制传播“Transactional”无法正常工作?

问题描述 投票:0回答:1

当存在以下调用链时:rest方法 -> service1的事务方法(

propagation=Requires_New
) -> service2的事务方法(
propagation=Mandatory
):

@Service
class Service1(
    private val service2: Service2
) {

    private val log = LoggerFactory.getLogger(this.javaClass)

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    fun method1() {
        log.error("Transaction for method1: " + TransactionAspectSupport.currentTransactionStatus().transactionName)
        service2.method2()
    }
}


@Service
class Service2 {

    private val log = LoggerFactory.getLogger(this.javaClass)

    @Transactional(propagation = Propagation.MANDATORY)
    fun method2() {
        log.error("Transaction for method2: " + TransactionAspectSupport.currentTransactionStatus().transactionName)
    }
}

日志打印以下内容(日志应该打印每个方法的当前事务的名称):

sb-repro     | 2024-02-20T13:20:25.000Z ERROR 1 --- [sb-repro] [   scheduling-1] c.r.s.persistence.service.Service1       : Transaction for method1: com.romankudryashov.sbrepro.persistence.service.Service1.method1
sb-repro     | 2024-02-20T13:20:25.000Z ERROR 1 --- [sb-repro] [   scheduling-1] c.r.s.persistence.service.Service2       : Transaction for method2: com.romankudryashov.sbrepro.persistence.service.Service2.method2

我认为这是错误的(考虑到

Mandatory
传播应该是
Support a current transaction, throw an exception if none exists
)并且
method2
的数据库事务应该是
com.romankudryashov.sbrepro.persistence.service.Service1.method1

我错了还是这是一个错误?

复制器在这里:https://github.com/rkudryashov/sb-repro。您只需拨打电话

http://localhost:8080/test

(无需构建原生镜像即可重现。)

spring spring-boot spring-data-jpa spring-data spring-transactions
1个回答
0
投票

我认为这是因为

TransactionAspectSupport.currentTransactionStatus().transactionName
对于嵌套方法调用的行为不一致

我稍微改变了代码:

@Service
class Service1(
    private val service2: Service2
) {

    private val log = LoggerFactory.getLogger(this.javaClass)

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    fun method1() {
        log.error("Name from TransactionAspectSupport: " + TransactionAspectSupport.currentTransactionStatus().transactionName)
        log.error("Name from TransactionSynchronizationManager: " + TransactionSynchronizationManager.getCurrentTransactionName())
        service2.method2()
    }
}

@Service
class Service2 {

    private val log = LoggerFactory.getLogger(this.javaClass)

    @Transactional
    fun method2() {
        log.error("Name from TransactionAspectSupport: " + TransactionAspectSupport.currentTransactionStatus().transactionName)
        log.error("Name from TransactionSynchronizationManager: " + TransactionSynchronizationManager.getCurrentTransactionName())
    }
}

现在打印:

2024-02-22T12:16:27.239+03:00 ERROR 14928 --- [sb-repro] [nio-8080-exec-1] c.r.s.persistence.service.Service1       : Name from TransactionAspectSupport: com.romankudryashov.sbrepro.persistence.service.Service1.method1
2024-02-22T12:16:27.239+03:00 ERROR 14928 --- [sb-repro] [nio-8080-exec-1] c.r.s.persistence.service.Service1       : Name from TransactionSynchronizationManager: com.romankudryashov.sbrepro.persistence.service.Service1.method1
2024-02-22T12:16:27.239+03:00 ERROR 14928 --- [sb-repro] [nio-8080-exec-1] c.r.s.persistence.service.Service2       : Name from TransactionAspectSupport: com.romankudryashov.sbrepro.persistence.service.Service2.method2
2024-02-22T12:16:27.239+03:00 ERROR 14928 --- [sb-repro] [nio-8080-exec-1] c.r.s.persistence.service.Service2       : Name from TransactionSynchronizationManager: com.romankudryashov.sbrepro.persistence.service.Service1.method1

也就是说

TransactionAspectSupport
TransactionSynchronizationManager
行为不同

如果我删除上面的

@Transactional
,一切都是正确的:
method2

© www.soinside.com 2019 - 2024. All rights reserved.