Spring Boot Configure and Use Two DataSources

后端 未结 9 2058
不思量自难忘°
不思量自难忘° 2020-11-22 04:26

How can I configure and use two data sources?

For example here is what I have for the first data source:

application.properties



        
相关标签:
9条回答
  • 2020-11-22 05:15

    I used mybatis - springboot 2.0 tech stack, solution:

    //application.properties - start
        sp.ds1.jdbc-url=jdbc:mysql://localhost:3306/mydb?useSSL=false
        sp.ds1.username=user
        sp.ds1.password=pwd
        sp.ds1.testWhileIdle=true
        sp.ds1.validationQuery=SELECT 1
        sp.ds1.driverClassName=com.mysql.jdbc.Driver
    
    
        sp.ds2.jdbc-url=jdbc:mysql://localhost:4586/mydb?useSSL=false
        sp.ds2.username=user
        sp.ds2.password=pwd
        sp.ds2.testWhileIdle=true
        sp.ds2.validationQuery=SELECT 1
        sp.ds2.driverClassName=com.mysql.jdbc.Driver
    
    //application.properties - end
    
    //configuration class
    
        @Configuration
        @ComponentScan(basePackages = "com.mypkg")
        public class MultipleDBConfig {
    
    
            public static final String SQL_SESSION_FACTORY_NAME_1 = "sqlSessionFactory1";
            public static final String SQL_SESSION_FACTORY_NAME_2 = "sqlSessionFactory2";
    
            public static final String MAPPERS_PACKAGE_NAME_1 = "com.mypg.mymapper1";
            public static final String MAPPERS_PACKAGE_NAME_2 = "com.mypg.mymapper2";
    
    
            @Bean(name = "mysqlDb1")
            @Primary
            @ConfigurationProperties(prefix = "sp.ds1")
            public DataSource dataSource1() {
                System.out.println("db1 datasource");
                return DataSourceBuilder.create().build();
            }
    
            @Bean(name = "mysqlDb2")
            @ConfigurationProperties(prefix = "sp.ds2")
            public DataSource dataSource2() {
                System.out.println("db2 datasource");
                return  DataSourceBuilder.create().build();
            }
    
            @Bean(name = SQL_SESSION_FACTORY_NAME_1)
            @Primary
            public SqlSessionFactory sqlSessionFactory1(@Qualifier("mysqlDb1") DataSource dataSource1) throws Exception {
                System.out.println("sqlSessionFactory1");
                SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
                sqlSessionFactoryBean.setTypeHandlersPackage(MAPPERS_PACKAGE_NAME_1);
                sqlSessionFactoryBean.setDataSource(dataSource1);
                SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
                sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
                sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
                return sqlSessionFactory;
            }
    
            @Bean(name = SQL_SESSION_FACTORY_NAME_2)
            public SqlSessionFactory sqlSessionFactory2(@Qualifier("mysqlDb2") DataSource dataSource2) throws Exception {
                System.out.println("sqlSessionFactory2");
                SqlSessionFactoryBean diSqlSessionFactoryBean = new SqlSessionFactoryBean();
                diSqlSessionFactoryBean.setTypeHandlersPackage(MAPPERS_PACKAGE_NAME_2);
                diSqlSessionFactoryBean.setDataSource(dataSource2);
                SqlSessionFactory sqlSessionFactory = diSqlSessionFactoryBean.getObject();
                sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
                sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
                return sqlSessionFactory;
            }
    
            @Bean
            @Primary
            public MapperScannerConfigurer mapperScannerConfigurer1() {
                System.out.println("mapperScannerConfigurer1");
                MapperScannerConfigurer configurer = new MapperScannerConfigurer();
                configurer.setBasePackage(MAPPERS_PACKAGE_NAME_1);
                configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_1);
                return configurer;
            }
    
            @Bean
            public MapperScannerConfigurer mapperScannerConfigurer2() {
                System.out.println("mapperScannerConfigurer2");
                MapperScannerConfigurer configurer = new MapperScannerConfigurer();
                configurer.setBasePackage(MAPPERS_PACKAGE_NAME_2);
                configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_2);
                return configurer;
            }
    
    
    
        }
    

    Note : 1)@Primary -> @primary

    2)---."jdbc-url" in properties -> After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName

    0 讨论(0)
  • 2020-11-22 05:17

    Update 2018-01-07 with Spring Boot 1.5.8.RELEASE

    Most answers do not provide how to use them (as datasource itself and as transaction), only how to config them.

    You can see the runnable example and some explanation in https://www.surasint.com/spring-boot-with-multiple-databases-example/

    I copied some code here.

    First you have to set application.properties like this

    #Database
    database1.datasource.url=jdbc:mysql://localhost/testdb
    database1.datasource.username=root
    database1.datasource.password=root
    database1.datasource.driver-class-name=com.mysql.jdbc.Driver
    
    database2.datasource.url=jdbc:mysql://localhost/testdb2
    database2.datasource.username=root
    database2.datasource.password=root
    database2.datasource.driver-class-name=com.mysql.jdbc.Driver
    

    Then define them as providers (@Bean) like this:

    @Bean(name = "datasource1")
    @ConfigurationProperties("database1.datasource")
    @Primary
    public DataSource dataSource(){
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name = "datasource2")
    @ConfigurationProperties("database2.datasource")
    public DataSource dataSource2(){
        return DataSourceBuilder.create().build();
    }
    

    Note that I have @Bean(name="datasource1") and @Bean(name="datasource2"), then you can use it when we need datasource as @Qualifier("datasource1") and @Qualifier("datasource2") , for example

    @Qualifier("datasource1")
    @Autowired
    private DataSource dataSource;
    

    If you do care about transaction, you have to define DataSourceTransactionManager for both of them, like this:

    @Bean(name="tm1")
    @Autowired
    @Primary
    DataSourceTransactionManager tm1(@Qualifier ("datasource1") DataSource datasource) {
        DataSourceTransactionManager txm  = new DataSourceTransactionManager(datasource);
        return txm;
    }
    
    @Bean(name="tm2")
    @Autowired
    DataSourceTransactionManager tm2(@Qualifier ("datasource2") DataSource datasource) {
        DataSourceTransactionManager txm  = new DataSourceTransactionManager(datasource);
        return txm;
    }
    

    Then you can use it like

    @Transactional //this will use the first datasource because it is @primary
    

    or

    @Transactional("tm2")
    

    This should be enough. See example and detail in the link above.

    0 讨论(0)
  • 2020-11-22 05:17

    My requirement was slightly different but used two data sources.

    I have used two data sources for same JPA entities from same package. One for executing DDL at the server startup to create/update tables and another one is for DML at runtime.

    The DDL connection should be closed after DDL statements are executed, to prevent further usage of super user previlleges anywhere in the code.

    Properties

    spring.datasource.url=jdbc:postgresql://Host:port
    ddl.user=ddluser
    ddl.password=ddlpassword
    dml.user=dmluser
    dml.password=dmlpassword
    spring.datasource.driver-class-name=org.postgresql.Driver
    

    Data source config classes

    //1st Config class for DDL Data source

      public class DatabaseDDLConfig {
            @Bean
            public LocalContainerEntityManagerFactoryBean ddlEntityManagerFactoryBean() {
                LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
                PersistenceProvider persistenceProvider = new 
                org.hibernate.jpa.HibernatePersistenceProvider();
                entityManagerFactoryBean.setDataSource(ddlDataSource());
                entityManagerFactoryBean.setPackagesToScan(new String[] { 
                "com.test.two.data.sources"});
                HibernateJpaVendorAdapter vendorAdapter = new 
                HibernateJpaVendorAdapter();
                entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
                HashMap<String, Object> properties = new HashMap<>();
                properties.put("hibernate.dialect", 
                "org.hibernate.dialect.PostgreSQLDialect");
                properties.put("hibernate.physical_naming_strategy", 
                "org.springframework.boot.orm.jpa.hibernate.
                SpringPhysicalNamingStrategy");
                properties.put("hibernate.implicit_naming_strategy", 
                "org.springframework.boot.orm.jpa.hibernate.
                SpringImplicitNamingStrategy");
                properties.put("hibernate.hbm2ddl.auto", "update");
                entityManagerFactoryBean.setJpaPropertyMap(properties);
                entityManagerFactoryBean.setPersistenceUnitName("ddl.config");
                entityManagerFactoryBean.setPersistenceProvider(persistenceProvider);
                return entityManagerFactoryBean;
            }
    
    
        @Bean
        public DataSource ddlDataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
            dataSource.setUrl(env.getProperty("spring.datasource.url"));
            dataSource.setUsername(env.getProperty("ddl.user");
            dataSource.setPassword(env.getProperty("ddl.password"));
            return dataSource;
        }
    
        @Bean
        public PlatformTransactionManager ddlTransactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(ddlEntityManagerFactoryBean().getObject());
            return transactionManager;
        }
    }
    

    //2nd Config class for DML Data source

    public class DatabaseDMLConfig {
    
        @Bean
        @Primary
        public LocalContainerEntityManagerFactoryBean dmlEntityManagerFactoryBean() {
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            PersistenceProvider persistenceProvider = new org.hibernate.jpa.HibernatePersistenceProvider();
            entityManagerFactoryBean.setDataSource(dmlDataSource());
            entityManagerFactoryBean.setPackagesToScan(new String[] { "com.test.two.data.sources" });
            JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
            entityManagerFactoryBean.setJpaProperties(defineJpaProperties());
            entityManagerFactoryBean.setPersistenceUnitName("dml.config");
            entityManagerFactoryBean.setPersistenceProvider(persistenceProvider);
            return entityManagerFactoryBean;
        }
    
        @Bean
        @Primary
        public DataSource dmlDataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
            dataSource.setUrl(envt.getProperty("spring.datasource.url"));
            dataSource.setUsername("dml.user");
            dataSource.setPassword("dml.password");
            return dataSource;
        }
    
        @Bean
        @Primary
        public PlatformTransactionManager dmlTransactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(dmlEntityManagerFactoryBean().getObject());
            return transactionManager;
        }
    
    
      }
    

    //Usage of DDL data sources in code.

    public class DDLServiceAtStartup {
    
    //Import persistence unit ddl.config for ddl purpose.
    
    @PersistenceUnit(unitName = "ddl.config")
    private EntityManagerFactory entityManagerFactory;
    
    public void executeDDLQueries() throws ContentServiceSystemError {
        try {
            EntityManager entityManager = entityManagerFactory.createEntityManager();
            entityManager.getTransaction().begin();
            entityManager.createNativeQuery("query to create/update table").executeUpdate();
            entityManager.flush();
            entityManager.getTransaction().commit();
            entityManager.close();
    
            //Close the ddl data source to avoid from further use in code.
            entityManagerFactory.close();
        } catch(Exception ex) {}
    }
    

    //Usage of DML data source in code.

    public class DDLServiceAtStartup {
      @PersistenceUnit(unitName = "dml.config")
      private EntityManagerFactory entityManagerFactory;
    
      public void createRecord(User user) {
         userDao.save(user);
      }
    }
    
    0 讨论(0)
提交回复
热议问题