【问题标题】:Spring boot r2dbc transactional: which method to annotateSpring boot r2dbc transactional:注释哪个方法
【发布时间】:2021-04-25 09:18:53
【问题描述】:

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

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

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

如果我对控制器方法进行注释,事情会按预期工作,并且不会向表 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(),则事务不会按预期工作。将一行添加到表“b”。

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

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

【问题讨论】:

    标签: spring-boot spring-data-r2dbc r2dbc r2dbc-postgresql


    【解决方案1】:

    来自 Spring 参考文档:Using @Transactional

    在代理模式下(默认),只有外部方法调用 通过代理进入的被拦截。这意味着 自调用(实际上,目标对象中的一个方法调用 目标对象的另一种方法)不会导致实际 即使调用的方法标记为 @事务。此外,代理必须完全初始化以提供 预期的行为,所以你不应该在你的 初始化代码(即@PostConstruct)。

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

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

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

    【讨论】:

      猜你喜欢
      • 2018-02-23
      • 1970-01-01
      • 2017-02-05
      • 2019-07-12
      • 2019-06-15
      • 2017-12-06
      • 2015-01-07
      • 2011-09-07
      • 2020-03-29
      相关资源
      最近更新 更多