Spring boot 2.3 + Spring Data JPA配置多數據源

項目近期有個需求,要同時連接兩個數據庫,並且不同環境,數據庫種類還不同,我們有兩個數據庫,其中一個測試環境是oracle,生產環境又是postgre,另一個一直是postgre,調查了網上能搜到很多資料,基本上寫法都一致,比如https://blog.csdn.net/itguangit/article/details/78747969,但用在sb 2.3上會發現兩個問題,一個是EntityManagerFactoryBuilder在啓動時無法自動注入,雖然理論上sb會自動創建其實例,另一個是2.3中jpaProperties已經沒有getHibernateProperties這個方法了,花了兩天時間,發現一個外國人寫的帖子方法是適用於2.3這個版本的,發佈時間是去年,比較新,原帖見https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot-application/ ,但也不是沒有問題,需要再改造一下才能完全適應項目開發,下面是改造後的大致的代碼

  • application.yml
    spring:
      datasource:
        first:
          url: jdbc:postgresql://localhost:5432/sample
          driverClassName: org.postgresql.Driver
          username: postgres
          password: 111
        second:
          url: jdbc:oracle:thin:@//192.168.1.100:1521/orclpdb
          driverClassName: oracle.jdbc.OracleDriver
          username: webdba
          password: 111
      jpa:
        hibernate:
          ddl-auto: none
        show-sql: true

     

  • 數據源1的配置文件,postgre db
    需要注意的是,這裏的每個方法都要使用Primary的註解,只有一個配置文件需要如此 ,這個是sb規定,否則啓動時會報錯,貌似任意一個都可以指定成這樣的,不要被字面意思迷惑
    package com.xxx.config;
    
    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.sql.DataSource;
    
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = "com.xxx.repo.first", //當前數據源對應的repository的包名,每個數據源應該有獨立的包
            entityManagerFactoryRef = "firstEntityManagerFactory",
            transactionManagerRef= "firstTransactionManager"
    )
    public class FirstJpaConfig {
        @Bean
        @Primary
        @ConfigurationProperties("spring.datasource.first")
        public DataSourceProperties firstDataSourceProperties() {
            return new DataSourceProperties();
        }
    
        @Bean
        @Primary
        @ConfigurationProperties("spring.datasource.first.configuration")
        public DataSource firstDataSource() {
            return firstDataSourceProperties().initializeDataSourceBuilder()
                    .type(HikariDataSource.class).build();
        }
    
        @Primary
        @Bean(name = "firstEntityManagerFactory")
        public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(firstDataSource())
                    .packages("com.xxx.entity.first") //當前數據源對應的實體的包名,每個數據源應該有獨立的包
                    .build();
        }
    
        @Primary
        @Bean
        public PlatformTransactionManager firstTransactionManager(
                final @Qualifier("firstEntityManagerFactory") LocalContainerEntityManagerFactoryBean firstEntityManagerFactory) {
            return new JpaTransactionManager(firstEntityManagerFactory.getObject());
        }
    
        @Primary
        @Bean(name = "firstEntityManager")
    	//這個不是必須,但如果你想在service中注入一個EntityManager用於執行動態jql,這個就是必要的,否則,sb會不知道選擇哪個EntityManager實例使用,每個數據源對應一個實例
        public EntityManager entityManager(@Qualifier("firstEntityManagerFactory") EntityManagerFactory factory) {
            return factory.createEntityManager();
        }
    }
    
    

     

  • 數據源2的配置文件,oracle db,和第一個高度類似,不解釋了
    package com.xxx.config;
    
    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.sql.DataSource;
    
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = "com.xxx.repo.second",
            entityManagerFactoryRef = "secondEntityManagerFactory",
            transactionManagerRef= "secondTransactionManager"
    )
    public class SecondJpaConfig {
        @Bean
        @ConfigurationProperties("spring.datasource.second")
        public DataSourceProperties secondDataSourceProperties() {
            return new DataSourceProperties();
        }
    
        @Bean
        @ConfigurationProperties("spring.datasource.second.configuration")
        public DataSource secondDataSource() {
            return secondDataSourceProperties().initializeDataSourceBuilder()
                    .type(HikariDataSource.class).build();
        }
    
        @Bean(name = "secondEntityManagerFactory")
        public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory(EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(secondDataSource())
                    .packages("com.xxx.entity.second")
                    .build();
        }
    
        @Bean
        public PlatformTransactionManager secondTransactionManager(
                final @Qualifier("secondEntityManagerFactory") LocalContainerEntityManagerFactoryBean secondEntityManagerFactory) {
            return new JpaTransactionManager(secondEntityManagerFactory.getObject());
        }
    
        @Bean(name = "secondEntityManager")
        public EntityManager entityManager(@Qualifier("secondEntityManagerFactory") EntityManagerFactory factory) {
            return factory.createEntityManager();
        }
    }
    
    

     

原帖中使用的數據源實現類是dbcp,聽說目前性能最好的是Hikari數據源,我就替換了一下,測試運行良好。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章