1. 程式人生 > >Spring Boot多資料來源配置

Spring Boot多資料來源配置

  • 動機

    • 在最近的專案中,由於新專案要和老專案整合(新舊業務過渡),因此需要將的資料庫表與老資料庫表做資料庫同步。
  • 方案

    • 利用Spring Boot支援多資料來源的特性,配置兩個資料來源來實現該需求。(這篇部落格不討論業務層面的實現方式,只討論多資料來源的配置。)
  • 實現

    1. 新建兩個配置類(即加@Configuration註解的類),一個為PrimaryDatasourceConfig,用來配置本專案的資料來源;另一個叫SecondDatasourceCOnfig,用來配置需要同步的資料來源。程式碼如下:

      @Configuration
      public class PrimaryDatasourceConfig
      {
      @Bean(name = "primaryDataSource") @Primary @ConfigurationProperties(prefix = "primary.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } } @Configuration public class SecondDatasourceConfig { @Bean(name = "secondDataSource"
      ) @ConfigurationProperties(prefix = "second.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } }

      其中@Primary註解是用來指定優先使用的資料來源。
      @ConfigurationProperties是用來指定該資料遠,從application.properties中讀取字首為“XXX”的配置作為該資料來源的配置。
      並且由於這兩個資料來源的型別都是DataSource,因此我們需要為這兩個Bean指定不同的名稱,這樣能夠在後面注入的時候通過名稱來注入相應的Bean。

    2. 再新建兩個配置類,來配置EntityManager與JdbcTemplate。程式碼如下:

      @Configuration
      @EnableTransactionManagement(proxyTargetClass = true)//開啟註解管理方式
      @EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryPrimary",//指定LocalContainerEntityManagerFactoryBean
              transactionManagerRef = "transactionManagerPrimary",//指定使用哪個EntityManager
              basePackages = { "org.model" })//指定該資料來源對於的model包
      public class RepositoryPrimaryConfig {
      
          @Autowired
          private JpaProperties jpaProperties;
      
          @Autowired
          @Qualifier("primaryDataSource")//指定使用哪個資料來源
          private DataSource primaryDataSource;
      
          @Bean(name = "entityManagerPrimary")
          @Primary//由於這個資料來源是Primary,因此這裡配置的Bean都加上@Primary註解。
          //即在@Autowired時,沒有用指定@Qualifier指定哪個資料來源配置時,預設使用這個。
          public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
              return entityManagerFactory(builder).getObject()
                      .createEntityManager();
          }
      
          @Bean(name = "entityManagerFactoryPrimary")
          @Primary
          public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                  EntityManagerFactoryBuilder builder) {
              return builder.dataSource(primaryDataSource)
                      .properties(getVendorProperties(primaryDataSource))
                      .packages("org.model") // 設定實體類所在位置
                      .persistenceUnit("PrimaryPersistenceUnit")
                      .build();
          }  
      
          private Map<String, String> getVendorProperties(DataSource dataSource) {
              return jpaProperties.getHibernateProperties(dataSource);
          }
      
          @Bean(name = "transactionManagerPrimary")
          @Primary
          PlatformTransactionManager transactionManager(
                  EntityManagerFactoryBuilder builder) {
              return new JpaTransactionManager(
                      entityManagerFactory(builder).getObject());
          }
      
          @Bean
          @Primary
          public JdbcTemplate primaryJdbcTemplate(DataSource dataSource) {
              return new JdbcTemplate(dataSource);
          }
      }
      
      @Configuration
      @EnableTransactionManagement(proxyTargetClass = true)
      @EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactorySecond",
              transactionManagerRef = "transactionManagerSecond",
              basePackages = { "org.second" })
      public class RepositorySecondConfig {
      
          @Autowired
          private JpaProperties jpaProperties;
      
          @Autowired
          @Qualifier("secondDataSource")
          private DataSource secondDataSource;
      
          @Bean(name = "entityManagerSecond")
          public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
              return entityManagerFactory(builder).getObject()
                      .createEntityManager();
          }
      
          @Bean(name = "entityManagerFactorySecond")
          public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                  EntityManagerFactoryBuilder builder) {
              return builder.dataSource(secondDataSource)
                      .properties(getVendorProperties(jwcDataSource))
                      .packages("org.second") // 設定實體類所在位置
                      .persistenceUnit("SecondPersistenceUnit").build();
          }
      
          private Map<String, String> getVendorProperties(DataSource dataSource) {
              return jpaProperties.getHibernateProperties(dataSource);
          }
      
          @Bean(name = "transactionManagerSecond")
          PlatformTransactionManager transactionManager(
                  EntityManagerFactoryBuilder builder) {
              return new JpaTransactionManager(
                      entityManagerFactory(builder).getObject());
          }
      
          @Bean(name = "secondJdbcTemplate")
          public JdbcTemplate jdbcTemplate(
                  @Qualifier("secondDataSource") DataSource dataSource) {
              return new JdbcTemplate(dataSource);
          }
      }
    3. 當使用第二個資料來源的時候,@Autowired時用@Qualifier指定第二個資料來源即可。例如要注入jdbcTemplate。

      @Autowired
      @Qualifier("secondJdbcTemplate")
      private JdbcTemplate jdbcTemplate;

      如果沒有@Qualifier("secondJdbcTemplate"),預設指定Primary資料來源。