Spring boot r2dbc transactional:注释哪个方法

ant*_*wrx 7 spring-boot spring-data-r2dbc r2dbc r2dbc-postgresql

我使用 spring-boot 2.4.2 和 webflux 连接到 postgres 数据库。@Transactional我在使用时观察到一种我不明白的行为。

为了展示该行为,我创建了一个示例应用程序,尝试将行添加到两个表中;表“a”和表“b”。对表“a”的插入预计会因重复键冲突而失败。鉴于使用了事务性,我预计不会将任何行添加到表“b”中。

但是,根据我使用的注释方法,@Transactional我会得到不同的结果。

如果我注释控制器方法,一切都会按预期工作,并且不会向表 B 添加任何行。

    @PostMapping("/")
    @Transactional
    public Mono<Void> postEntities() {
        return demoService.doSomething();
    }
Run Code Online (Sandbox Code Playgroud)

演示服务如下所示:

    public Mono<Void> doSomething() {
        return internal();
    }


    public Mono<Void> internal() {
        Mono<EntityA> clash = Mono.just(EntityA.builder().name("clash").build()).flatMap(repositoryA::save);
        Mono<EntityB> ok = Mono.just(EntityB.builder().name("ok").build()).flatMap(repositoryB::save);
        return ok.and(clash);
    }
Run Code Online (Sandbox Code Playgroud)

如果我将@Transactional注释从控制器移至doSomething(),那么事务仍然按预期工作。但是,如果我将@Transactional注释移至internal(),则事务将无法按预期工作。一行被添加到表“b”中。

此示例的完整代码在这里:https ://github.com/alampada/pg-spring-r2dbc-transactional

我不明白为什么将注释移至internal()方法会导致事务处理出现问题。您能解释一下吗?

R.G*_*R.G 5

来自Spring参考文档:使用@Transactional

\n
\n

在代理模式(默认)下,仅拦截通过代理传入的外部方法调用。这意味着自调用(实际上,目标对象中的方法调用目标对象的其他方法)不会在运行时导致实际的事务,即使调用的方法标有@Transactional。此外,必须完全初始化代理才能提供预期的行为,因此您不应在初始化代码(即 @PostConstruct)中依赖此功能。

\n
\n

这里从doSomething()到internal()的调用是一个自调用。

\n

请注意,Spring Framework\xe2\x80\x99s 声明性事务支持是通过 AOP 代理启用的。

\n

Spring 参考文档:了解 AOP 代理将清楚地说明为什么自调用在代理上不起作用。请通读以\n 开头的部分,这里要理解的关键是 main(..) 中的客户端代码

\n