SpringBoot配置多数据源一

背景

随着业务的发展,在开发过程中,需要在一个工程里连接多个数据库,并兼容springBoot原本的与mybatis整合。

思路

看源码,过程大体是: 创建DataSource — 根据DataSource创建SqlSessionFactory — 根据SqlSessionFactory创建SqlSessionTemplate

这里,我将多个数据库作为多个数据源创建出来,并根据@MapperScan扫描多个包的机制,将不同的SqlSessionTemplate创建出来。

过程

创建第一个数据源:

@Configuration
@MapperScan(basePackages = "com.business.db1.mapper", sqlSessionFactoryRef = "db1SqlSessionFactory")
public class Db1DataSourceConfig {
    @Bean(name = "db1DataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource getDateSource() {
        DataSource dataSource = DataSourceBuilder.create().build();
        return dataSource;
   }
    @Bean(name = "db1SqlSessionFactory")
    @Primary
    public SqlSessionFactory memberSqlSessionFactory(@Qualifier("db1DataSource") DataSource datasource)throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com.business.db1/*.xml"));
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        return bean.getObject();
    }
    @Bean("db1SqlSessionTemplate")
    @Primary
    public SqlSessionTemplate memberSqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sessionFactory) {
        return new SqlSessionTemplate(sessionFactory);
    }
}

创建第二个数据源:

@Configuration
@MapperScan(basePackages = "com.business.db2.mapper", sqlSessionFactoryRef = "db2SqlSessionFactory")
public class Db2DataSourceConfig {
    @Bean(name = "db2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource getDateSource() {
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "db2SqlSessionFactory")
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("db2DataSource") DataSource datasource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com.business.db2/*.xml"));
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        return bean.getObject();
    }
    @Bean("db2SqlSessionTemplate")
    public SqlSessionTemplate primarySqlSessionTemplate(
            @Qualifier("db2SqlSessionFactory") SqlSessionFactory sessionFactory) {
        return new SqlSessionTemplate(sessionFactory);
    }
}

配置之后就可以。

新问题

我的db1数据源是用sharding做的分库分表,需要同时在一个工程里访问一个分库分表的数据源,一个普通的数据源。

使用后了解sharding配置后最终也是创建一个DataSource出来,交给spring托管;那我是不是将上面的db1里的数据源换成sharding的配置就可以了呢? 说干就干。

@Configuration
@MapperScan(basePackages = "com.business.db1.mapper", sqlSessionFactoryRef = "db1SqlSessionFactory")
public class Db1DataSourceConfig {

    @Bean(name = "db1DataSource")
    @Primary
    public DataSource getShardingDataSource(ShardingSliceProperties shardingSliceProperties) throws SQLException {

        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        TableRuleConfiguration tableRuleConfiguration = new TableRuleConfiguration(shardingSliceProperties.getSliceTable(),
                shardingSliceProperties.getSliceDatabase() + "_${0..15}." + shardingSliceProperties.getSliceTable() + "_${0..127}");
        // 设置表规则
        shardingRuleConfig.getTableRuleConfigs().add(tableRuleConfiguration);

        // 设置分库规则
        shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration(
                shardingSliceProperties.getSliceDatabaseKey(), new OrderDatabaseAlgorithm()));

        // 设置分表规则
        shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration(
                shardingSliceProperties.getSliceTableKey(), new OrderTableAlgorithm()));

        // 配置分库数据源
        Map<String, DataSource> dataSourceMap = new HashMap<>();
        for (int i = 0; i < 16; i++) {
            HikariConfig hikariConfig = new HikariConfig();
            hikariConfig.setMinimumIdle(5);
            hikariConfig.setMaximumPoolSize(25);
            hikariConfig.setUsername(shardingSliceProperties.getUsername());
            hikariConfig.setPassword(shardingSliceProperties.getPassword());
            hikariConfig.setDriverClassName(shardingSliceProperties.getDriverClassName());
            hikariConfig.setJdbcUrl(shardingSliceProperties.getJdbcUrl()+ "_" + i);
            HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
            dataSourceMap.put(shardingSliceProperties.getSliceDatabase() + "_" + i, hikariDataSource);
        }

        Properties props = new Properties();
        // 设置显示sql
        props.put(ShardingPropertiesConstant.SQL_SHOW.getKey(), String.valueOf(Boolean.TRUE));

        // 配置默认数据源
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(shardingSliceProperties.getDriverClassName());
        hikariConfig.setJdbcUrl(shardingSliceProperties.getJdbcUrl());
        hikariConfig.setUsername(shardingSliceProperties.getUsername());
        hikariConfig.setPassword(shardingSliceProperties.getPassword());
        hikariConfig.setMaximumPoolSize(25);
        hikariConfig.setMinimumIdle(5);
        HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
        dataSourceMap.put(shardingSliceProperties.getSliceDatabase(), hikariDataSource);
        shardingRuleConfig.setDefaultDataSourceName(shardingSliceProperties.getSliceDatabase());
        DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, props);
        return dataSource;
    }

    @Bean(name = "db1SqlSessionFactory")
    @Primary
    public SqlSessionFactory memberSqlSessionFactory(@Qualifier("db1DataSource") DataSource datasource)throws Exception {

        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com.business.db1/*.xml"));

        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        return bean.getObject();
    }

    @Bean("db1SqlSessionTemplate")
    @Primary
    public SqlSessionTemplate memberSqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sessionFactory) {
        return new SqlSessionTemplate(sessionFactory);
    }
}

启动报错,DataSouce NullPointException。 debug运行了一下,发现执行了org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration这个自动配置,在启动类exclude这个自动配置类搞定。

启动测试没问题。搞定。