Spring Boot多MySQL数据源配置异常:查询非主库表报错
这个问题我之前也碰到过,本质是Spring Boot对@Primary数据源的默认优先级规则导致的:当你把db1设为@Primary后,所有没有明确指定数据源的持久化操作,都会默认使用db1的数据库连接。所以你查询db2的table4时,实际是在db1库中查找该表,自然会抛出SQL Error: 1146, SQLState: 42S02的表不存在异常;而把@Primary切换到db2后,默认连接变成db2,查询就能正常执行了。
要彻底解决这个问题,核心是让操作db2的代码明确关联到对应的db2数据源配置,而不是默认复用Primary的db1配置。下面是具体的解决步骤:
1. 确保db2的数据源配置完全独立且隔离
你需要为db2单独配置一套完整的持久化Bean,包括DataSource、EntityManagerFactory和TransactionManager,且这些Bean不要添加@Primary注解,同时要明确指定对应的实体类包路径和持久化单元名称:
// db2数据源配置类 @Configuration @EnableJpaRepositories( basePackages = "com.yourpackage.db2.repositories", // db2的Repository所在包 entityManagerFactoryRef = "db2EntityManagerFactory", transactionManagerRef = "db2TransactionManager" ) public class Db2DataSourceConfig { @Bean(name = "db2DataSource") @ConfigurationProperties(prefix = "spring.datasource.db2") // 对应application.yml中的db2配置前缀 public DataSource db2DataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "db2EntityManagerFactory") public LocalContainerEntityManagerFactoryBean db2EntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("db2DataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.yourpackage.db2.entities") // db2的实体类所在包 .persistenceUnit("db2PersistenceUnit") // 持久化单元名称,后续会用到 .build(); } @Bean(name = "db2TransactionManager") public PlatformTransactionManager db2TransactionManager( @Qualifier("db2EntityManagerFactory") EntityManagerFactory entityManagerFactory) { return new JpaTransactionManager(entityManagerFactory); } }
同时,db1的Primary配置也要明确指定自己的包路径,避免和db2的配置冲突:
@Configuration @Primary @EnableJpaRepositories( basePackages = "com.yourpackage.db1.repositories", // db1的Repository所在包 entityManagerFactoryRef = "db1EntityManagerFactory", transactionManagerRef = "db1TransactionManager" ) public class Db1DataSourceConfig { // 对应的db1 DataSource、EntityManagerFactory、TransactionManager配置,带@Primary }
2. 为db2的Repository/DAO指定对应的事务管理器
在操作db2的Repository上,通过@Transactional注解明确指定使用db2的事务管理器:
@Repository @Transactional(value = "db2TransactionManager") // 关联db2的事务管理器 public interface Table4Repository extends JpaRepository<Table4, Long> { // 你的查询方法 }
如果是使用EntityManager直接操作,记得通过@PersistenceContext指定db2的持久化单元:
@Service public class Table4Service { @PersistenceContext(unitName = "db2PersistenceUnit") // 指定db2的持久化单元 private EntityManager db2EntityManager; public Table4 getTable4ById(Long id) { return db2EntityManager.find(Table4.class, id); } }
3. 验证实体类的表配置(可选但推荐)
确保db2的实体类Table4上的@Table注解正确指定了数据库(如果数据源配置已经指定了db2,这一步不是必须,但能避免混淆):
@Entity @Table(name = "table4", catalog = "db2") // 明确指定所属数据库 public class Table4 { // 实体字段和映射配置 }
完成以上配置后,操作db2的代码就会明确使用db2的数据源连接,不会再复用Primary的db1连接,自然就能正常查询table4了。
内容的提问来源于stack exchange,提问作者Krish

