在 Spring 中使用多个数据源

Posted

技术标签:

【中文标题】在 Spring 中使用多个数据源【英文标题】:Using Multiple DataSources With Spring 【发布时间】:2014-09-26 07:39:52 【问题描述】:

我正在开发一个使用 Spring Data JPA 的 Spring Boot 应用程序,并且需要连接到两个不同的数据库,但我遇到了一个问题。当应用程序启动时,它抛出一个异常,基本上说明它不知道要使用哪个数据源。这是我的配置类的 sn-p。数据库属性(例如 url、用户名、密码)在 application.properties 文件中定义。

@Configuration
@ComponentScan(basePackages = "com.test")
@EnableJpaRepositories(basePackages = "com.test.jpa.repository")
@EnableAutoConfiguration
@EnableTransactionManagement
public class AppConfig 

@Bean(name = "dataSource1")
DataSource dataSource1(@Value("$db1.driverClassName") String db1DriverClassName,  @Value("$db1.url") String db1Url, @Value("$db1.username") String db1Username, @Value("$db1.password") String db1Password) 
    DataSource dataSource = new DataSource();

    dataSource.setDriverClassName(db1DriverClassName);
    dataSource.setUrl(db1Url);
    dataSource.setUsername(db1Username);
    dataSource.setPassword(db1Password);

    return dataSource;


@Bean(name = "dataSource2")
DataSource dataSource2(@Value("$db2.driverClassName") String db2DriverClassName, @Value("$db2.url") String db2Url, @Value("$db2.username") String db2Username, @Value("$db2.password") String db2Password) 
    DataSource dataSource = new DataSource();

    dataSource.setDriverClassName(db2DriverClassName);
    dataSource.setUrl(db2Url);
    dataSource.setUsername(db2Username);
    dataSource.setPassword(db2Password);

    return dataSource;


@Bean(name = "jpaVendorAdapter")
HibernateJpaVendorAdapter jpaVendorAdapter() 
    HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();

    jpaVendorAdapter.setDatabase(Database.ORACLE);
    jpaVendorAdapter.setShowSql(false);
    jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");

    return jpaVendorAdapter;


@Bean(name = "entityManagerFactory")
@Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSource1") DataSource dataSource, HibernateJpaVendorAdapter jpaVendorAdapter) 
    LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();

    entityManagerFactory.setDataSource(dataSource);
    entityManagerFactory.setPersistenceXmlLocation("classpath:persistence.xml");
    entityManagerFactory.setPersistenceUnitName("springdatajpa");
    entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);

    return entityManagerFactory;


@Bean(name = "transactionManager")
JpaTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory) 
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory.getObject());

    return transactionManager;

这是被抛出的异常:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.dataSource; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSource1,dataSource2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
at com.wth.service.logging.Application.main(Application.java:11)

我的entityManagerFactory 方法使用@Autowired 注释和dataSource 参数前面带有@Qualifier("dataSource1") 注释,所以这应该可以工作。我以前在其他 Spring 应用程序中做过这个并且没有任何问题。这是我第一次遇到这个异常。

是否有人对可能导致此问题的原因有任何想法/想法?

谢谢, 克里斯

【问题讨论】:

尝试删除@EnableAutoConfiguration。看起来您正在自己配置 bean。你得到的例外是在 Spring 类中,看起来不像在你的类中。 【参考方案1】:

为了让这个工作,我使用了以下内容:

@SpringBootApplication(exclude =  
  DataSourceAutoConfiguration.class, 
  HibernateJpaAutoConfiguration.class, 
  JpaRepositoriesAutoConfiguration.class, 
  DataSourceTransactionManagerAutoConfiguration.class)
public class App...

这相当于:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude =  
  DataSourceAutoConfiguration.class, 
  HibernateJpaAutoConfiguration.class,
  JpaRepositoriesAutoConfiguration.class, 
  DataSourceTransactionManagerAutoConfiguration.class)

然后我为每个数据源创建了一个单独的配置类,其定义如下:

@Configuration
@EnableJpaRepositories(
  entityManagerFactoryRef="fooEntityManagerFactory", 
  transactionManagerRef="fooTransactionManager")
public class FooConfig 

  public static final String FOO_QUALIFIER = "Foo";

  @Bean @Qualifier(FOO_QUALIFIER)
  public DataSource fooDataSource()  ... 

  @Bean @Qualifier(FOO_QUALIFIER)
  public EntityManagerFactory fooEntityManagerFactory()  ... 

  @Bean @Qualifier(FOO_QUALIFIER)
  public PlatformTransactionManager fooTransactionManager(
    @Qualifier(FOO_QUALIFIER) EntityManagerFactory emf)  ... 

【讨论】:

【参考方案2】:

您确实在 Spring 的 DataSourceAutoConfiguration.class 中遇到了异常。 由于您是自己配置数据源,请尝试删除 @EnableAutoConfiguration

DataSourceAutoConfiguration 查找类型 DataSource(不带限定符)

【讨论】:

【参考方案3】:

正如 Rafal Borowiec 在回复我的类似帖子 here 所建议的那样,修改您的自动配置以排除 JPA 存储库配置。

@EnableAutoConfiguration(exclude = JpaRepositoriesAutoConfiguration.class)

【讨论】:

【参考方案4】:

只需从您的配置中删除 @EnableAutoConfiguration!

【讨论】:

以上是关于在 Spring 中使用多个数据源的主要内容,如果未能解决你的问题,请参考以下文章

Spring初始化多个数据库

使用多个where子句在spring数据jpa中删除

多数据源 spring怎么管理事务的

在春季批处理(spring-boot-1.5.2.RELEASE)中使用多个数据源在启动时引发异常

Spring JPA:在 CI 环境中使用多个数据库测试 DAO 层

如何使用 Spring 和 JPA 设置多个数据源