【问题标题】:Spring Boot, Spring Data JPA with multiple DataSourcesSpring Boot,具有多个数据源的 Spring Data JPA
【发布时间】:2014-12-06 03:09:46
【问题描述】:

我正在尝试使用 Spring Boot 和 Spring Data JPA 将每个 @Repositories 连接到不同的 DataSource。我使用以下http://xantorohara.blogspot.com/2013/11/spring-boot-jdbc-with-multiple.html 作为参考。这是我尝试使用 Spring Data JPA 实现类似解决方案的代码。

CustomerDbConfig.java(第一个数据源连接)

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "orderEntityManager",
        transactionManagerRef = "orderTransactionManager",
        basePackages = {"com.mm.repository.customer"})
public class CustomerDbConfig {

    @Bean(name = "customerEntityManager")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] {"com.mm.domain.customer"});

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalJpaProperties());
        em.setPersistenceUnitName("customerPersistence");
        em.setPackagesToScan("com.mm.domain.customer");

        return em;
    }

    Properties additionalJpaProperties(){
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        properties.setProperty("hibernate.show_sql", "true");

        return properties;
    }

    @Bean
    public DataSource dataSource(){
        return DataSourceBuilder.create()
                .url("jdbc:h2:mem:customer:H2")
                .driverClassName("org.h2.Driver")
                .username("sa")
                .password("")
                .build();
    }   

    @Bean(name = "customerTransactionManager")
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);

        return transactionManager;
    }
}

CustomerDbConfig.java(第二个数据源)

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "orderEntityManager",
        transactionManagerRef = "orderTransactionManager",
        basePackages = {"com.mm.repository.customer"})
public class CustomerDbConfig {

    @Bean(name = "customerEntityManager")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] {"com.mm.domain.customer"});

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalJpaProperties());
        em.setPersistenceUnitName("customerPersistence");
        em.setPackagesToScan("com.mm.domain.customer");

        return em;
    }

    Properties additionalJpaProperties(){
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        properties.setProperty("hibernate.show_sql", "true");

        return properties;
    }

    @Bean
    public DataSource dataSource(){
        return DataSourceBuilder.create()
                .url("jdbc:h2:mem:customer:H2")
                .driverClassName("org.h2.Driver")
                .username("sa")
                .password("")
                .build();
    }   

    @Bean(name = "customerTransactionManager")
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);

        return transactionManager;
    }
}

Customer.java(模型)

@Entity
@Table(name = "customer")
@Data
@EqualsAndHashCode(exclude = {"id"})
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "age", nullable = false)
    private Integer age;

....

Order.java(模型)

@Entity
@Table(name = "order")
@Data
@EqualsAndHashCode(exclude = {"id"})
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name = "code", nullable = false)
    private Integer code;

    @Column(name = "quality", nullable = false)
    private Integer quality;

...

CustomerRepository.java

public interface CustomerRepository extends JpaRepository<Customer, Integer>{

}

OrderRepository.java

public interface OrderRepository extends JpaRepository<Order, Integer> {

}

最后,Application.java

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringApplication{

       public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }

        @Bean
        public ServletRegistrationBean h2Console() {
            ServletRegistrationBean reg = new ServletRegistrationBean(new WebServlet(), "/console/*");
            reg.setLoadOnStartup(1);
            return reg;
        }
}

在开始时会抛出以下异常

-10-10 15:45:24.757 ERROR 1549 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerTransactionManager' defined in class path resource [com/mm/boot/multidb/CustomerConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.persistence.EntityManagerFactory]: : No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
    at com.mm.boot.multidb.Application.main(Application.java:17)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:974)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
    ... 18 common frames omitted

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerTransactionManager' defined in class path resource [com/mm/boot/multidb/CustomerConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.persistence.EntityManagerFactory]: : No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
    at com.mm.boot.multidb.Application.main(Application.java:17)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:974)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
    ... 18 more

示例的完整代码可以在 GitHub (https://github.com/tonym2105/samples/tree/master/boot-multidb-sample) 上找到

提前感谢您的帮助。

【问题讨论】:

  • 首先你做了太多的配置,Spring Boot 可以为你做。查看docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
  • 你还有同样的问题吗?我之所以问,是因为我检查了您的代码,它对我来说只需稍作更改(与您在问题中陈述的错误无关)
  • 它只有在应用程序属性中设置 spring.jpa.open_in_view = false 后才有效,如下面的答案所示。

标签: java spring jpa spring-data spring-boot


【解决方案1】:

还有另一种方法可以使用 @EnableAutoConfiguration 和 application.properties 来拥有多个数据源。

基本上将多个dataSource配置信息放在application.properties上,并通过@EnableAutoConfiguration为第一个dataSource自动生成默认设置(dataSource和entityManagerFactory)。但是对于下一个数据源,通过属性文件中的信息手动创建数据源、实体管理器工厂和事务管理器。

以下是我设置两个数据源的示例。 第一个 dataSource 由 @EnableAutoConfiguration 设置,它只能分配给一个配置,而不是多个。这将由 DataSourceTransactionManager 生成“transactionManager”,看起来是注释生成的默认 transactionManager。但是,我已经看到仅针对默认 DataSourceTransactionManager 以及当有多个事务管理器时,调度线程池中的线程上的事务没有开始问题。 因此,我也通过 JpaTransactionManager 为第一个数据源手动创建了 transactionManager,并分配了“transactionManager”bean 名称和默认 entityManagerFactory。第一个数据源的 JpaTransactionManager 肯定解决了 ScheduledThreadPool 线程上的奇怪事务问题。

Spring Boot 1.3.0.RELEASE 更新

我发现我之前使用 @EnableAutoConfiguration 为默认数据源进行的配置在使用 Spring Boot 1.3 版本查找 entityManagerFactory 时存在问题。在我介绍了我自己的事务管理器之后,@EnableAutoConfiguration 可能不会生成默认的 entityManagerFactory。 所以现在我自己创建了 entityManagerFactory。所以我不需要使用@EntityScan。所以看起来我越来越远离@EnableAutoConfiguration 的设置。

第二个数据源是在没有@EnableAutoConfiguration 的情况下设置的,并通过手动方式创建“anotherTransactionManager”。

由于有多个从 PlatformTransactionManager 扩展的 transactionManager,我们应该指定在每个 @Transactional annotation 上使用哪个 transactionManager

默认存储库配置

@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactory",
        transactionManagerRef = "transactionManager",
        basePackages = {"com.mysource.repository"})
public class RepositoryConfig {
    @Autowired
    JpaVendorAdapter jpaVendorAdapter;

    @Autowired
    DataSource dataSource;

    @Bean(name = "entityManager")
    public EntityManager entityManager() {
        return entityManagerFactory().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactory")
    public EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource);
        emf.setJpaVendorAdapter(jpaVendorAdapter);
        emf.setPackagesToScan("com.mysource.model");
        emf.setPersistenceUnitName("default");   // <- giving 'default' as name
        emf.afterPropertiesSet();
        return emf.getObject();
    }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(entityManagerFactory());
        return tm;
    }
}

另一个存储库配置

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "anotherEntityManagerFactory",
        transactionManagerRef = "anotherTransactionManager",
        basePackages = {"com.mysource.anothersource.repository"})
public class AnotherRepositoryConfig {
    @Autowired
    JpaVendorAdapter jpaVendorAdapter;

    @Value("${another.datasource.url}")
    private String databaseUrl;

    @Value("${another.datasource.username}")
    private String username;

    @Value("${another.datasource.password}")
    private String password;

    @Value("${another.dataource.driverClassName}")
    private String driverClassName;

    @Value("${another.datasource.hibernate.dialect}")
    private String dialect;

    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource(databaseUrl, username, password);
        dataSource.setDriverClassName(driverClassName);
        return dataSource;
    }

    @Bean(name = "anotherEntityManager")
    public EntityManager entityManager() {
        return entityManagerFactory().createEntityManager();
    }

    @Bean(name = "anotherEntityManagerFactory")
    public EntityManagerFactory entityManagerFactory() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", dialect);

        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource());
        emf.setJpaVendorAdapter(jpaVendorAdapter);
        emf.setPackagesToScan("com.mysource.anothersource.model");   // <- package for entities
        emf.setPersistenceUnitName("anotherPersistenceUnit");
        emf.setJpaProperties(properties);
        emf.afterPropertiesSet();
        return emf.getObject();
    }

    @Bean(name = "anotherTransactionManager")
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory());
    }
}

application.properties

# database configuration
spring.datasource.url=jdbc:h2:file:~/main-source;AUTO_SERVER=TRUE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.continueOnError=true
spring.datasource.initialize=false

# another database configuration
another.datasource.url=jdbc:sqlserver://localhost:1433;DatabaseName=another;
another.datasource.username=username
another.datasource.password=
another.datasource.hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect 
another.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

为@Transactional注解选择合适的transactionManager

第一个数据源的服务

@Service("mainService")
@Transactional("transactionManager")
public class DefaultDataSourceServiceImpl implements DefaultDataSourceService       
{

   //

}

另一个数据源的服务

@Service("anotherService")
@Transactional("anotherTransactionManager")
public class AnotherDataSourceServiceImpl implements AnotherDataSourceService 
{

   //

}

【讨论】:

  • 抱歉,这是我的错字。我不得不重命名一些东西,我错过了那个。这不是问题,但感谢您的努力。
  • 这救了我!想补充一点,当逐字跟进时,这在 1.5.2.RELEASE 上成功。
  • 我能够对两个不同的数据源进行事务处理,而无需在任何实现类中使用 @Transactional 注释。这种行为是预期的吗?使用 Spring-Boot 1.5.6.RELEASE
  • 我相信spring通过带有@Transactional注释的AOP自动代理来管理事务。我在 Spring Data Rest 中看到了一些像 @RepositoryRestResource 这样的 Spring 技术,在没有 @Transactional 的情况下自动工作。我猜想在编译期间使用默认事务设置可能会生成一些代码和层。但是我想知道如何将不同的 transactionManager 分配给需要使用不同类型数据库的服务或存储库而不指定它
【解决方案2】:

这是我的解决方案。基于 spring-boot.1.2.5.RELEASE。

application.properties

first.datasource.driver-class-name=com.mysql.jdbc.Driver
first.datasource.url=jdbc:mysql://127.0.0.1:3306/test
first.datasource.username=
first.datasource.password=
first.datasource.validation-query=select 1

second.datasource.driver-class-name=com.mysql.jdbc.Driver
second.datasource.url=jdbc:mysql://127.0.0.1:3306/test2
second.datasource.username=
second.datasource.password=
second.datasource.validation-query=select 1

DataSourceConfig.java

@Configuration
public class DataSourceConfig {
    @Bean
    @Primary
    @ConfigurationProperties(prefix="first.datasource")
    public DataSource firstDataSource() {
        DataSource ds =  DataSourceBuilder.create().build();
        return ds;
    }

    @Bean
    @ConfigurationProperties(prefix="second.datasource")
    public DataSource secondDataSource() {
        DataSource ds =  DataSourceBuilder.create().build();
        return ds;
    }
}

【讨论】:

  • 你如何引用这个?我已经做到了这一点,但是我不知道如何通过 JPA “召唤”第二个数据源。我认为它可能在实体注释或查询参数中。
  • 这样。 @Autowired @Qualifier("firstDataSource") 私有数据源 firstDataSource; @Autowired @Qualifier("secondDataSource") private DataSource secondDataSource;
  • 如何使用它创建或召唤第二个实体管理器?我做这件事的时候很糟糕
  • 有人设法让它工作吗?要将自定义数据源与 JPA 链接,还是人们只是假设没有实际示例?
  • 我注意到这个解决方案只有在两个数据库都映射到同一个 JDBC 驱动程序时才有效。但是,当您有两个不同的数据源连接到两个不同的驱动程序时,它将不起作用。例如:一个驱动程序使用 MariaDB 驱动程序,另一个使用 ibm DB2Driver...
【解决方案3】:

我检查了您在 GitHub 上提供的源代码。配置中有几个错误/拼写错误。

在 CustomerDbConfig / OrderDbConfig 你应该参考 customerEntityManager 并且包应该指向现有包:

@Configuration
@EnableJpaRepositories(
    entityManagerFactoryRef = "customerEntityManager",
    transactionManagerRef = "customerTransactionManager",
    basePackages = {"com.mm.boot.multidb.repository.customer"})
public class CustomerDbConfig {

customerEntityManager 和 orderEntityManager 中要扫描的包都没有指向正确的包:

em.setPackagesToScan("com.mm.boot.multidb.model.customer");

注入正确的 EntityManagerFactory 也不起作用。应该是:

@Bean(name = "customerTransactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory customerEntityManager){

}

以上是导致问题和异常的原因。在 @Bean 方法中提供名称时,您可以确定您得到了正确的 EMF 注入。

我做的最后一件事是禁用 JpaRepositories 的自动配置:

@EnableAutoConfiguration(exclude = JpaRepositoriesAutoConfiguration.class)

通过所有修复,应用程序将按您预期的方式启动!

【讨论】:

  • 首先,谢谢。我现在得到一个“org.springframework.beans.factory.NoUniqueBeanDefinitionException:没有定义类型 [javax.persistence.EntityManagerFactory] ​​的合格 bean:预期的单个匹配 bean,但发现 2:customerEntityManager,orderEntityManager”异常。 GitHub 更新了建议的更改。
  • EntityManagerInViewInterceptor 自动配置导致了这种情况。您应该可以通过在应用程序属性中提供 spring.jpa.open_in_view = false 轻松禁用它。
  • 那行得通。但是禁用该属性意味着什么?再次感谢您的帮助。
  • "Spring Web 请求拦截器,它将 JPA EntityManager 绑定到线程以完成请求的整个处理。用于“在视图中打开 EntityManager”模式,即允许在 Web 视图中延迟加载,尽管原始交易已经完成。”
  • 两个实体都是在一个数据库中创建的。我在 H2 和 MySQL 中都注意到了这一点。非常感谢任何帮助。
【解决方案4】:

感谢 Steve Park 和 Rafal Borowiec 的回答,我的代码可以正常工作,但是,我遇到了一个问题:DriverManagerDataSource 是一个“简单”的实现,不会给你一个 ConnectionPool(检查http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/datasource/DriverManagerDataSource.html)。

因此,我将返回 DataSource 的函数替换为 secondDB

public DataSource <secondaryDB>DataSource() {
    // use DataSourceBuilder and NOT DriverManagerDataSource 
    // as this would NOT give you ConnectionPool
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.url(databaseUrl);
    dataSourceBuilder.username(username);
    dataSourceBuilder.password(password);
    dataSourceBuilder.driverClassName(driverClassName);
    return dataSourceBuilder.build();
}

另外,如果您不需要EntityManager,您可以同时删除entityManager()@Bean 注释。

另外,您可能希望删除配置类的 basePackages 注释:使用 factoryBean.setPackagesToScan() 调用对其进行维护就足够了。

【讨论】:

    【解决方案5】:

    我在Spring Boot JPA Multiple Data Sources Example写了一篇完整的文章。在本文中,我们将学习如何在一个典型的 Spring Boot Web 应用程序中配置多个数据源并连接到多个数据库。我们将使用 Spring Boot 2.0.5、JPA、Hibernate 5、Thymeleaf 和 H2 数据库来构建一个简单的 Spring Boot 多数据源 Web 应用程序。

    【讨论】:

      【解决方案6】:

      不知道为什么,但它有效。两个配置是一样的,把xxx改成你的名字就好了。

      @Configuration
      @EnableTransactionManagement
      @EnableJpaRepositories(
          entityManagerFactoryRef = "xxxEntityManager",
          transactionManagerRef = "xxxTransactionManager",
          basePackages = {"aaa.xxx"})
       public class RepositoryConfig {
      @Autowired
      private Environment env;
      
      @Bean
      @Primary
      @ConfigurationProperties(prefix="datasource.xxx")
      public DataSource xxxDataSource() {
          return DataSourceBuilder.create().build();
      }
      
      @Bean
      public LocalContainerEntityManagerFactoryBean xxxEntityManager() {
          LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
          em.setDataSource(xxxDataSource());
          em.setPackagesToScan(new String[] {"aaa.xxx"});
      
          HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
          em.setJpaVendorAdapter(vendorAdapter);
          HashMap<String, Object> properties = new HashMap<String, Object>();
          properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
          properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
          properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
          em.setJpaPropertyMap(properties);
      
          return em;
      }
      
      @Bean(name = "xxxTransactionManager")
      public PlatformTransactionManager xxxTransactionManager() {
          JpaTransactionManager tm = new JpaTransactionManager();
          tm.setEntityManagerFactory(xxxEntityManager().getObject());
          return tm;
      }
      

      }

      【讨论】:

      • datasource.xxx.url = datasource.xxx.username = datasource.xxx.password = datasource.xxx.driver-class-name = com.mysql.jdbc.Driver
      猜你喜欢
      • 1970-01-01
      • 2017-10-28
      • 1970-01-01
      • 2015-07-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-03
      • 1970-01-01
      相关资源
      最近更新 更多