首页 文章

Spring Boot配置和使用两个DataSource

提问于
浏览
107

我是Spring和Spring Boot的新手 . 如何配置和使用两个数据源 .

例如,这是第一个数据源的内容 .

application.properties

#first db
spring.datasource.url = [url]
spring.datasource.username = [username]
spring.datasource.password = [password]
spring.datasource.driverClassName = oracle.jdbc.OracleDriver

#second db ...

Application class

@SpringBootApplication
public class SampleApplication {
private static final Logger logger = LoggerFactory.getLogger(SampleApplication.class);


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

@Autowired
SampleRepository repo;

@PostConstruct
public void testDriving(){
    logger.debug(repo.findSomeSample("id", "other"));
    }
}

如何修改application.properties以添加其他数据源?如何将其自动装配以供其他仓库使用?

8 回答

  • 8

    干得好

    #first db
    spring.datasource.url = [url]
    spring.datasource.username = [username]
    spring.datasource.password = [password]
    spring.datasource.driverClassName = oracle.jdbc.OracleDriver
    
    #second db ...
    spring.secondDatasource.url = [url]
    spring.secondDatasource.username = [username]
    spring.secondDatasource.password = [password]
    spring.secondDatasource.driverClassName = oracle.jdbc.OracleDriver
    
    
    @Bean
    @Primary
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    @ConfigurationProperties(prefix="spring.secondDatasource")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
  • 14

    参考the official documentation


    创建多个数据源与创建第一个数据源的工作方式相同 . 如果您使用JDBC或JPA的默认自动配置(那么任何@Autowired注入将获取一个),您可能希望将其中一个标记为@Primary .

    @Bean
    @Primary
    @ConfigurationProperties(prefix="datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    @ConfigurationProperties(prefix="datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
  • 3

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

    大多数答案没有提供如何使用它们(作为数据源本身和事务),只提供如何配置它们 .

    您可以在https://www.surasint.com/spring-boot-with-multiple-databases-example/中看到可运行的示例和一些说明

    我在这里复制了一些代码 .

    首先,您必须像这样设置application.properties

    #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
    

    然后将它们定义为提供者(@Bean),如下所示:

    @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();
    }
    

    请注意,我有@Bean(name =“datasource1”)和@Bean(name =“datasource2”),那么当我们需要数据源为@Qualifier(“datasource1”)和@Qualifier(“datasource2”)时,你可以使用它,例如

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

    如果您关心事务,则必须为它们定义DataSourceTransactionManager,如下所示:

    @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;
    }
    

    然后就可以使用它了

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

    要么

    @Transactional("tm2")
    

    这应该足够了 . 请参阅上面链接中的示例和详细信息 .

  • 1

    这是完整的解决方案

    #First Datasource (DB1)
    db1.datasource.url: url
    db1.datasource.username:user
    db1.datasource.password:password
    
    #Second Datasource (DB2)
    db2.datasource.url:url
    db2.datasource.username:user
    db2.datasource.password:password
    

    由于我们要访问两个不同的数据库(db1,db2),我们需要单独配置每个数据源配置,如:

    public class DB1_DataSource {
    @Autowired
    private Environment env;
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean db1EntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(db1Datasource());
        em.setPersistenceUnitName("db1EntityManager");
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        HashMap<string, object=""> properties = new HashMap<>();
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.show-sql",
                env.getProperty("jdbc.show-sql"));
        em.setJpaPropertyMap(properties);
        return em;
    }
    
    @Primary
    @Bean
    public DataSource db1Datasource() {
    
        DriverManagerDataSource dataSource
                = new DriverManagerDataSource();
        dataSource.setDriverClassName(
                env.getProperty("jdbc.driver-class-name"));
        dataSource.setUrl(env.getProperty("db1.datasource.url"));
        dataSource.setUsername(env.getProperty("db1.datasource.username"));
        dataSource.setPassword(env.getProperty("db1.datasource.password"));
    
        return dataSource;
    }
    
    @Primary
    @Bean
    public PlatformTransactionManager db1TransactionManager() {
    
        JpaTransactionManager transactionManager
                = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(
                db1EntityManager().getObject());
        return transactionManager;
    }
    }
    

    Second Datasource :

    public class DB2_DataSource {
    
    @Autowired
    private Environment env;
    
    @Bean
    public LocalContainerEntityManagerFactoryBean db2EntityManager() {
        LocalContainerEntityManagerFactoryBean em
                = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(db2Datasource());
        em.setPersistenceUnitName("db2EntityManager");
        HibernateJpaVendorAdapter vendorAdapter
                = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        HashMap<string, object=""> properties = new HashMap<>();
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.show-sql",
                env.getProperty("jdbc.show-sql"));
        em.setJpaPropertyMap(properties);
        return em;
    }
    
    @Bean
    public DataSource db2Datasource() {
        DriverManagerDataSource dataSource
                = new DriverManagerDataSource();
        dataSource.setDriverClassName(
                env.getProperty("jdbc.driver-class-name"));
        dataSource.setUrl(env.getProperty("db2.datasource.url"));
        dataSource.setUsername(env.getProperty("db2.datasource.username"));
        dataSource.setPassword(env.getProperty("db2.datasource.password"));
    
        return dataSource;
    }
    
    @Bean
    public PlatformTransactionManager db2TransactionManager() {
        JpaTransactionManager transactionManager
                = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(
                db2EntityManager().getObject());
        return transactionManager;
    }
    }
    

    在这里你可以在我的博客上找到完整的例子:Spring Boot with Multiple DataSource Configuration

  • 0

    我使用了mybatis - springboot 2.0技术堆栈,解决方案:

    //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;
            }
    
    
    
        }
    

    注意:1)@ Primary-> @primary

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

  • 0

    如果两个数据源位于同一个数据库位置/服务器上,则对下面的方法使用@Primary注释时效果很好 .

    @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();
    }
    

    如果数据源位于不同的服务器上,则最好使用@Component和@Primary注释 . 以下代码段适用于不同位置的两个不同数据源

    database1.datasource.url = jdbc:mysql://127.0.0.1:3306/db1
    database1.datasource.username = root
    database1.datasource.password = mysql
    database1.datasource.driver-class-name=com.mysql.jdbc.Driver
    
    database2.datasource1.url = jdbc:mysql://192.168.113.51:3306/db2
    database2.datasource1.username = root
    database2.datasource1.password = mysql
    database2.datasource1.driver-class-name=com.mysql.jdbc.Driver
    
    @Configuration
    @Primary
    @Component
    @ComponentScan("com.db1.bean")
    class DBConfiguration1{
        @Bean("db1Ds")
        @ConfigurationProperties(prefix="database1.datasource")
        public DataSource primaryDataSource() {
            return DataSourceBuilder.create().build();
        }
    
    }
    
    @Configuration
    @Component
    @ComponentScan("com.db2.bean")
    class DBConfiguration2{
        @Bean("db2Ds")
        @ConfigurationProperties(prefix="database2.datasource1")
        public DataSource primaryDataSource() {
            return DataSourceBuilder.create().build();
        }
    
    }
    
  • 138

    My requirement was slightly different but used two data sources.

    我为同一个包中的相同JPA实体使用了两个数据源 . 一个用于在服务器启动时执行DDL以创建/更新表,另一个用于在运行时用于DML .

    执行DDL语句后应关闭DDL连接,以防止在代码中的任何位置进一步使用超级用户previlleges .

    属性

    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
    

    数据源配置类

    // DDL数据源的第一个Config类

    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;
        }
    }
    

    // DML数据源的第二个Config类

    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;
        }
    
    
      }
    

    //在代码中使用DDL数据源 .

    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) {}
    }
    

    //在代码中使用DML数据源 .

    public class DDLServiceAtStartup {
      @PersistenceUnit(unitName = "dml.config")
      private EntityManagerFactory entityManagerFactory;
    
      public void createRecord(User user) {
         userDao.save(user);
      }
    }
    
  • -1
    # Here '1stDB' is the database name
    spring.datasource.url=jdbc:mysql://localhost/A
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    
    
    # Here '2ndDB' is the database name
    spring.second-datasourcee.url=jdbc:mysql://localhost/B
    spring.second-datasource.username=root
    spring.second-datasource.password=root
    spring.second-datasource.driver-class-name=com.mysql.jdbc.Driver
    
    
        @Bean
        @Primary
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource firstDataSource() {
            return DataSourceBuilder.create().build();
        }
    
        @Bean
        @ConfigurationProperties(prefix = "spring.second-datasource")
        public DataSource secondDataSource() {
           return DataSourceBuilder.create().build();
        }
    

相关问题