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

Spring Boot集成Spring R2DBC多数据源查询异常排查

问题描述

我开发了一个连接fo_pgdb和if_pgdb两个Schema的Spring Boot服务,基于Spring R2DBC实现多数据源配置,但遇到如下异常:

  • 查询fo_pgdb的BID_LINES表中ID为123、345的记录可正常返回结果;
  • 查询if_pgdb的BID_LINES表中ID为567、8910的记录返回空集,但这些ID在if_pgdb的对应表中实际存在;
  • 使用ID123、345查询if_pgdb的BID_LINES表时,返回的却是fo_pgdb表中的对应记录。

已确认两个数据源的连接URL配置正确,请问可能的问题是什么?

代码示例
@Configuration
@EnableR2dbcRepositories(entityOperationsRef = "foEntityTemplate", basePackages = "com.r2dbc.poc.repository")
public class FODatabaseConfig {

    //@Value("${spring.r2dbc.fo.connection.url}")
    private String url = "r2dbc:postgresql://username:password@database-dev-fo-css-rr-db.corp.com:1200/fo_pgdb";

    @Bean
    @Qualifier("foConnectionFactory")
    public ConnectionFactory foConnectionFactory() {
        return ConnectionFactories.get(url);
    }

    @Bean
    public R2dbcEntityOperations foEntityTemplate(@Qualifier("foConnectionFactory") ConnectionFactory connectionFactory) {
        DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE);
        DatabaseClient databaseClient = DatabaseClient.builder()
                .connectionFactory(connectionFactory)
                .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory())
                .build();

        return new R2dbcEntityTemplate(databaseClient, strategy);
    }
    
}

@Configuration
@EnableR2dbcRepositories(entityOperationsRef = "ifEntityTemplate")
public class IFDatabaseConfig {


    //@Value("${spring.r2dbc.if.connection.url}")
    private String url = "r2dbc:postgresql://username:password@database-blue-if-CSS-db.corp.com:1200/if_pgdb";

    @Bean
    @Qualifier("ifConnectionFactory")
    public ConnectionFactory ifConnectionFactory() {
        return ConnectionFactories.get(url);
    }

    @Bean
    public R2dbcEntityOperations ifEntityTemplate(@Qualifier("ifConnectionFactory") ConnectionFactory connectionFactory) {
        DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE);
        DatabaseClient databaseClient = DatabaseClient.builder()
                .connectionFactory(connectionFactory)
                .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory())
                .build();

        return new R2dbcEntityTemplate(databaseClient, strategy);
    }
}

@Service
@RequiredArgsConstructor
public class CrewMemberSchedulePeriodPaymentService {

    private final FOCrewMemberBidLineRepository foCrewMemberBidlineRepository;

    private final IFCrewMemberBidLineRepository ifCrewMemberBidLineRepository;

    public Flux<FOCrewMemberBidLine> getFOBidLines(List<Long> id) {
        return foCrewMemberBidlineRepository.findAllById(id);
    }

    public Flux<IFCrewMemberBidLine> getIFBidLines(List<Long> id) {
       return ifCrewMemberBidLineRepository.findAllById(id);
    }

}

@Repository
public interface FOCrewMemberBidLineRepository extends R2dbcRepository<FOCrewMemberBidLine, Long> {

    @Override
    Flux<FOCrewMemberBidLine> findAllById(Iterable<Long> longs);
}


@Repository
public interface IFCrewMemberBidLineRepository extends R2dbcRepository<IFCrewMemberBidLine, Long> {
    @Override
    Flux<IFCrewMemberBidLine> findAllById(Iterable<Long> longs);
}

@Table(value = "BID_LINES")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class FOCrewMemberBidLine {

    @Id
    @Column(value = "bidlinseqnumber")
    private Long bidlinseqnumber;

    @Column(value = "bidlinschedperiod")
    private String bidlinschedperiod;
}

@Table(value = "BID_LINES")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class IFCrewMemberBidLine {

    @Id
    @Column(value = "bidlinseqnumber")
    private Long bidlinseqnumber;

    @Column(value = "bidlinschedperiod")
    private String bidlinschedperiod;
}
问题分析与解决方案

核心问题1:Repository未正确绑定对应数据源

IFDatabaseConfig类的@EnableR2dbcRepositories没有指定basePackages或basePackageClasses属性,导致Spring无法区分不同数据源对应的Repository。默认情况下,所有Repository都会使用第一个加载的数据源(即FO的数据源),这就解释了为什么查询IF的Repository却返回FO的数据。

修复方案:
给IFDatabaseConfig的@EnableR2dbcRepositories指定专属的包路径或Repository类,确保两个数据源的Repository被正确划分:

@Configuration
@EnableR2dbcRepositories(
        entityOperationsRef = "ifEntityTemplate",
        basePackageClasses = IFCrewMemberBidLineRepository.class // 或者指定专属包如"com.r2dbc.poc.repository.if"
)
public class IFDatabaseConfig {
    // ... 原有代码
}

同时建议给FODatabaseConfig的basePackages也做精准划分,比如指定com.r2dbc.poc.repository.fo,并将两个Repository分别放到对应子包下,避免范围重叠。

核心问题2:实体类未指定Schema

两个实体类的@Table注解仅指定了表名BID_LINES,未明确对应的Schema。当数据库存在多个Schema时,默认会使用连接用户的默认Schema,可能导致查询到错误Schema下的表。

修复方案:
在@Table注解中明确指定Schema:

// FO实体类
@Table(value = "BID_LINES", schema = "fo_pgdb")
// ... 其他注解

// IF实体类
@Table(value = "BID_LINES", schema = "if_pgdb")
// ... 其他注解

也可以在数据源URL中指定默认Schema(但更推荐在实体类上明确指定,避免数据源配置与实体耦合):
比如FO的URL改为:r2dbc:postgresql://username:password@database-dev-fo-css-rr-db.corp.com:1200/fo_pgdb?currentSchema=fo_pgdb

额外验证点

  1. 确认两个数据源的连接用户拥有对应Schema的查询权限;
  2. 配置logging.level.org.springframework.r2dbc=DEBUG打印SQL日志,验证实际执行的SQL是否查询了正确的Schema和表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 10:20:32