Spring boot r2dbc transactional: 注释哪个方法

Spring boot r2dbc transactional: which method to annotate

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

为了展示该行为,我创建了一个示例应用程序,它尝试向两个 table 中添加行; table“a”和table“b”。插入 table "a" 预计会因重复键违规而失败。鉴于使用了交易,我希望没有行被添加到 table "b".

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

如果我注释控制器方法,事情会按预期工作,并且没有行添加到 table B.

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

DemoService 看起来像这样:

    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);
    }

如果我将 @Transactional 注释从控制器移至 doSomething(),那么事务仍会按预期工作。 但是,如果我将 @Transactional 注释移至 internal(),则事务不会按预期工作。 table "b".

添加一行

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

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

来自 Spring 参考文档:Using @Transactional

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, @PostConstruct).

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

请注意 Spring 框架的声明式事务支持是通过 AOP 代理启用的。

Spring 参考文档:Understanding AOP Proxies 将阐明为什么自调用不适用于代理。请通读以以下开头的部分 这里要理解的关键是 main(..)

中的客户端代码