You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux中R2DBCRepository使用@Query插入数据失败

问题分析与解决方案

可能的失败原因

  • 异步操作未被订阅/错误未处理:R2DBC基于Reactor异步非阻塞模型,void返回值的方法不会触发操作执行,且异常会被静默吞噬。因为Reactor的数据流只有在被订阅时才会执行,没有订阅的话插入操作根本没运行,就算运行出现异常也没有渠道抛出。
  • Repository泛型的复合键映射问题:你的Repository继承了R2dbcRepository<Test, testEmbeddedId>,如果testEmbeddedId这个复合键类的映射不符合R2DBC要求(比如未正确实现equals/hashCode、字段映射错误),可能导致上下文初始化时存在隐性错误,影响后续操作执行。
  • 事务配置失效:R2DBC的@Transactional需要依赖正确配置的R2dbcTransactionManager,如果事务管理器未配置或配置错误,事务不会生效,也可能导致操作无反馈。

替代方案

1. 修改Repository方法的返回值

将void改为Mono<Integer>(返回受影响行数)或Mono<Void>,确保操作被订阅并能捕获异常:

@Repository("testRepository")
public interface TestRepository extends R2dbcRepository<Test, testEmbeddedId> {

    @Modifying
    @Query(value = "insert into test(id, name, status, created_date) VALUES ('b128f97d-d52c-4677-8746-00e2959c9ec6', 'c', 'd', '2022-10-28')")
    @Transactional
    Mono<Integer> insertData();
}

调用时必须订阅这个Mono才能触发执行并处理结果/异常:

testRepository.insertData()
    .subscribe(
        rows -> System.out.println("成功插入 " + rows + " 条数据"),
        error -> {
            System.err.println("插入失败:");
            error.printStackTrace();
        }
    );

2. 用@IdClass替代@Embedded处理复合键

如果必须使用复合键,可以尝试用@IdClass注解代替@Embedded,将复合键的字段直接定义在实体类中,同时创建对应的主键类:

// 主键类,需实现equals和hashCode
public class TestEmbeddedId implements Serializable {
    private UUID id;
    private String name;
    // getter、setter、equals、hashCode实现
}

// 实体类
@Table("test")
@IdClass(TestEmbeddedId.class)
public class Test {
    @Id
    private UUID id;
    @Id
    private String name;
    private String status;
    private LocalDate createdDate;
    // getter、setter
}

之后Repository可以正常继承R2dbcRepository<Test, TestEmbeddedId>,尝试用标准的save方法插入数据,避免自定义查询的问题。

3. 直接使用DatabaseClient执行操作

绕开Spring Data R2DBC Repository,用DatabaseClient直接执行SQL,更灵活且能明确处理异常:

@Component
public class TestDataService {

    private final DatabaseClient databaseClient;

    public TestDataService(DatabaseClient databaseClient) {
        this.databaseClient = databaseClient;
    }

    public Mono<Integer> insertTestData() {
        return databaseClient.sql("INSERT INTO test(id, name, status, created_date) VALUES (:id, :name, :status, :createdDate)")
                .bind("id", UUID.fromString("b128f97d-d52c-4677-8746-00e2959c9ec6"))
                .bind("name", "c")
                .bind("status", "d")
                .bind("createdDate", LocalDate.of(2022, 10, 28))
                .fetch()
                .rowsUpdated();
    }
}

调用时同样需要订阅Mono来触发执行并处理结果。

内容的提问来源于stack exchange,提问作者lahirumw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 18:21:27