Spring Boot 3.4.3 多数据源配置实战:解决 dynamic-datasource 与 PostgreSQL 冲突问题

张开发
2026/5/30 6:46:36 15 分钟阅读
Spring Boot 3.4.3 多数据源配置实战:解决 dynamic-datasource 与 PostgreSQL 冲突问题
Spring Boot 3.4.3 多数据源配置实战解决 dynamic-datasource 与 PostgreSQL 冲突问题一、问题背景与现象在 Spring Boot 3.4.3 项目中我们需要同时使用多个数据源2个 MySQL 数据源agent、auth使用 dynamic-datasource 进行动态切换1个独立的 PostgreSQL 数据源供 Spring AI 的 PgVectorStore 使用遇到的问题DS注解完全不生效所有数据库操作都强行使用 PostgreSQL 连接报错ERROR: relation ai_user does not existPostgreSQL 里没有 MySQL 的表二、问题根因分析1. dynamic-datasource 的自动配置机制dynamic-datasource的DynamicDataSourceAutoConfiguration会自动扫描 Spring 容器中所有的DataSourceBean并将它们纳入管理。当容器中存在多个DataSource时如果没有明确指定主数据源就会产生冲突。2. 配置优先级问题手动创建的pgVectorDataSource虽然名字不叫dataSourcedynamic-datasource扫描到。由于它是容器中第一个被创建的数据源被误当成了默认主数据源。3. 配置隔离不彻底即使将 PostgreSQL 配置移出spring.datasource层级dynamic-datasource的自动配置依然会扫描容器中手动创建的pgVectorDataSourceBean。三、失败的解决方案分析1. 排除 DataSourceAutoConfigurationSpringBootApplication(exclude DataSourceAutoConfiguration.class) public class Application { // 无效dynamic-datasource 有自己的自动配置机制 }2. 添加 strict: true 配置spring: datasource: dynamic: strict: true datasource: agent: url: jdbc:mysql://localhost:3306/agent auth: url: jdbc:mysql://localhost:3306/auth无效原因strict: true只检查指定的数据源是否存在不会阻止dynamic-datasource扫描容器中已有的DataSourceBean。3. 移出 PostgreSQL 配置# 从 spring: datasource: pgvector: url: jdbc:postgresql://localhost:5432/vector_db # 改为 spring: pgvector: url: jdbc:postgresql://localhost:5432/vector_db部分有效避免了从配置文件读取但容器中的 Bean 依然会被扫描。四、最终解决方案手动配置 DynamicDataSource1. 配置类完整代码Configuration public class DataSourceConfig { /** * 手动创建动态数据源并标记为 Primary * 确保 Spring 容器将其作为默认主数据源 */ Bean Primary public DynamicRoutingDataSource dynamicDataSource( DynamicDataSourceProperties properties) { // 创建动态路由数据源 DynamicRoutingDataSource dataSource new DynamicRoutingDataSource(); // 从配置文件中读取 MySQL 数据源配置 MapString, DataSourceProperty datasourceMap properties.getDatasource(); MapObject, Object targetDataSources new HashMap(); // 只加载配置文件中定义的 MySQL 数据源 for (Map.EntryString, DataSourceProperty entry : datasourceMap.entrySet()) { String poolName entry.getKey(); DataSourceProperty dataSourceProperty entry.getValue(); // 创建 Hikari 数据源 HikariDataSource hikariDataSource new HikariDataSource(); hikariDataSource.setJdbcUrl(dataSourceProperty.getUrl()); hikariDataSource.setUsername(dataSourceProperty.getUsername()); hikariDataSource.setPassword(dataSourceProperty.getPassword()); hikariDataSource.setDriverClassName(dataSourceProperty.getDriverClassName()); targetDataSources.put(poolName, hikariDataSource); } // 设置目标数据源 dataSource.setTargetDataSources(targetDataSources); // 设置默认数据源第一个配置的数据源 String primary properties.getPrimary(); if (primary ! null targetDataSources.containsKey(primary)) { dataSource.setDefaultTargetDataSource(targetDataSources.get(primary)); } else if (!targetDataSources.isEmpty()) { dataSource.setDefaultTargetDataSource( targetDataSources.values().iterator().next()); } return dataSource; } /** * PostgreSQL 向量数据库数据源 * 独立配置不参与动态数据源管理 * 不加 Primary 注解 */ Bean(pgVectorDataSource) public DataSource pgVectorDataSource( Value(${spring.pgvector.url}) String url, Value(${spring.pgvector.username}) String username, Value(${spring.pgvector.password}) String password) { HikariDataSource dataSource new HikariDataSource(); dataSource.setJdbcUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setDriverClassName(org.postgresql.Driver); dataSource.setPoolName(pgvector-pool); return dataSource; } /** * 为 Spring AI 提供 PostgreSQL 数据源 */ Bean public PgVectorStore pgVectorStore( Qualifier(pgVectorDataSource) DataSource dataSource) { return new PgVectorStore(dataSource); } }2. 配置文件# application.yml spring: # dynamic-datasource 配置只包含 MySQL 数据源 datasource: dynamic: primary: agent # 默认数据源 strict: true # 严格模式 datasource: agent: url: jdbc:mysql://localhost:3306/agent username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver auth: url: jdbc:mysql://localhost:3306/auth username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # PostgreSQL 独立配置不在 datasource 层级下 pgvector: url: jdbc:postgresql://localhost:5432/vector_db username: postgres password: postgres123五、解决方案的核心原理1. 明确的主数据源标记手动创建的DynamicDataSource加了Primary注解强制 Spring 容器将其作为默认主数据源。pgVectorDataSource只是一个普通的DataSourceBean没有Primary不会再被当成默认数据源。2. 完全控制数据源加载手动从DynamicDataSourceProperties读取配置文件中的agent和auth数据源只将这两个 MySQL 数据源加入DynamicRoutingDataSource的targetDataSources。pgVectorDataSource完全独立不参与动态数据源的管理。3. 绕过自动配置的不确定性dynamic-datasource的自动配置会尝试智能加载容器中的数据源但这种智能在多数据源场景下容易出错。手动配置后我们明确指定了动态数据源的内容和优先级没有任何歧义。六、最终架构总结数据源管理方式用途数据库类型agentdynamic-datasource手动配置Agent 业务库MySQLauthdynamic-datasource手动配置用户认证库MySQLpgVectorDataSource独立手动配置不参与动态管理Spring AI 向量库PostgreSQL七、关键配置原则动态数据源必须手动创建并标记Primary确保 Spring 容器能正确识别主数据源第三方库专用数据源必须独立配置不加Primary注解避免被误用配置完全隔离不同用途的数据源在配置层级上要彻底分离避免自动配置的智能行为在多数据源复杂场景下手动配置比自动配置更可靠八、使用示例Service public class UserService { // 使用 agent 数据源 DS(agent) public ListUser getAgentUsers() { return userMapper.selectList(null); } // 使用 auth 数据源 DS(auth) public ListUser getAuthUsers() { return userMapper.selectList(null); } // 使用 PostgreSQL 数据源通过特定 Bean Autowired Qualifier(pgVectorDataSource) private DataSource pgVectorDataSource; public void vectorOperation() { // 使用 pgVectorDataSource 进行向量操作 } }九、总结Spring Boot 多数据源配置的核心在于明确的数据源管理和优先级控制。通过手动配置DynamicDataSource并标记Primary我们可以完全控制数据源的加载和切换逻辑避免自动配置带来的不确定性。对于需要独立使用的第三方库数据源如 Spring AI 的 PostgreSQL应该完全隔离配置不参与动态数据源的管理体系。这种配置方式虽然代码量稍多但提供了最高的可控性和可维护性特别适合生产环境中的复杂多数据源场景。

更多文章