Spring Boot系列之多数据源配置

概述

项目开发中,经常遇到需要连接多个数据源的情况。

实现

直接给出代码。第一数据源配置:

import com.baomidou.mybatisplus.entity.GlobalConfiguration;
import com.baomidou.mybatisplus.mapper.LogicSqlInjector;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import com.aaa.cbd.platform.octopus.agg.dao.utils.DESDecryptutil;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Slf4j
@Configuration
@Data
@Primary
@MapperScan(basePackages = "com.aaa.cbd.platform.octopus.agg.dao.mapper.primary",
        sqlSessionFactoryRef = "sqlSessionFactoryBean")
public class PrimaryDataSourceConfig {

    @Value("${datasource.primary.mapperLocations}")
    private String[] thirdMapperLocations;

    @Value("${datasource.primary.url}")
    private String url;
    @Value("${datasource.primary.username}")
    private String userName;
    @Value("${datasource.primary.password}")
    private String password;
    @Value("${datasource.primary.driverClassName}")
    private String driverClassName;

    @Value("${datasource.primary.hikari.autoCommit}")
    private boolean autoCommit;
    @Value("${datasource.primary.hikari.poolName}")
    private String poolName;
    @Value("${datasource.primary.hikari.minimumIdle}")
    private int minIdle;
    @Value("${datasource.primary.hikari.maximumPoolSize}")
    private int maxPoolSize;

    /**
     * primary datasource 数据源属性、连接池属性
     */
    @Bean(name = "dataSource", destroyMethod = "close")
    public HikariDataSource dataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(driverClassName);
        hikariConfig.setJdbcUrl(url);
        hikariConfig.setUsername(userName);
        // 此处可使用DES简单加密
        hikariConfig.setPassword(password);
        hikariConfig.setPoolName(poolName);
        hikariConfig.setAutoCommit(autoCommit);
        hikariConfig.addDataSourceProperty("cachePrepStmts", "true");
        hikariConfig.addDataSourceProperty("prepStmtCacheSize", "250");
        hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        hikariConfig.addDataSourceProperty("useServerPrepStmts", "true");

        hikariConfig.setMinimumIdle(minIdle);
        hikariConfig.setMaximumPoolSize(maxPoolSize);
        hikariConfig.setConnectionTestQuery("SELECT 1");

        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        log.info("======== third dataSource: {} =========", dataSource);
        return dataSource;
    }

    /**
     * sql会话工场
     */
    @Bean(name = "sqlSessionFactoryBean")
    public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dataSource") HikariDataSource dataSource) {
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(ResourceUtil.mapperLocations(thirdMapperLocations));

        GlobalConfiguration config = new GlobalConfiguration();
        config.setDbColumnUnderline(true);
        config.setRefresh(false);
        config.setSqlInjector(new LogicSqlInjector());

        sqlSessionFactoryBean.setGlobalConfig(config);
        return sqlSessionFactoryBean;
    }

    /**
     * primary事务管理器
     */
    @Bean(name = "dataSourceTransactionManager")
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dataSource") HikariDataSource dataSource) {
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(dataSource);
        return manager;
    }

}

第三个数据源:

@Slf4j
@Configuration
@Data
@MapperScan(basePackages = "com.aaa.cbd.platform.octopus.agg.dao.mapper.third", sqlSessionFactoryRef = "thirdSqlSessionFactoryBean")
public class ThirdDataSourceConfig {

    @Value("${datasource.third.mapperLocations}")
    private String[] thirdMapperLocations;

    /**
     * 自定义数据源配置
     */
    @Value("${datasource.third.url}")
    private String url;

    @Value("${datasource.third.username}")
    private String userName;

    @Value("${datasource.third.password}")
    private String password;

    @Value("${datasource.third.driverClassName}")
    private String driverClassName;

    @Value("${datasource.third.hikari.autoCommit}")
    private boolean autoCommit;

    @Value("${datasource.third.hikari.poolName}")
    private String poolName;

    @Value("${datasource.third.hikari.minimumIdle}")
    private int minIdle;

    @Value("${datasource.third.hikari.maximumPoolSize}")
    private int maxPoolSize;

    /**
     * third datasource 数据源属性、连接池属性
     */
    @Bean(name = "thirdDataSource", destroyMethod = "close")
    public HikariDataSource secondaryDataSource() {
        HikariConfig config = new HikariConfig();
        config.setDriverClassName(driverClassName);
        config.setJdbcUrl(url);
        config.setUsername(userName);
        config.setPassword(password);
        config.setPoolName(poolName);
        config.setAutoCommit(autoCommit);
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.addDataSourceProperty("useServerPrepStmts", "true");

        config.setMinimumIdle(minIdle);
        config.setMaximumPoolSize(maxPoolSize);
        config.setConnectionTestQuery("SELECT 1");

        HikariDataSource dataSource = new HikariDataSource(config);
        log.info("======== supplier-log dataSource: {} =========", dataSource);
        return dataSource;
    }

    /**
     * third sql 会话工场
     */
    @Bean(name = "thirdSqlSessionFactoryBean")
    public MybatisSqlSessionFactoryBean secondarySqlSessionFactoryBean(@Qualifier("thirdDataSource") HikariDataSource dataSource) {
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setMapperLocations(ResourceUtil.mapperLocations(thirdMapperLocations));

        GlobalConfiguration config = new GlobalConfiguration();
        config.setDbColumnUnderline(true);
        config.setRefresh(false);
        config.setSqlInjector(new LogicSqlInjector());

        factoryBean.setGlobalConfig(config);
        return factoryBean;
    }

    /**
     * third 事务管理器
     */
    @Bean(name = "thirdDataSourceTransactionManager")
    public DataSourceTransactionManager secondaryDataSourceTransactionManager(@Qualifier("thirdDataSource") HikariDataSource dataSource) {
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(dataSource);
        return manager;
    }

}

配置文件application.yml

spring:
  # 排除datasource与mybatis自动装配
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
      - org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
      - org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration

# multi datasource
datasource:
  primary:
    mapperLocations: classpath*:mybatis/primary/*Mapper.xml
    driverClassName: com.mysql.cj.jdbc.Driver
    hikari:
      autoCommit: true
      poolName: ds-primary-pool
      minimumIdle: 10
      maximumPoolSize: 10
  third:
    mapperLocations: classpath*:mybatis/third/*Mapper.xml
    driverClassName: com.mysql.cj.jdbc.Driver
    hikari:
      autoCommit: true
      poolName: ds-third-pool
      minimumIdle: 10
      maximumPoolSize: 50

数据源配置类扫描:

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

@Slf4j
public class ResourceUtil {
    private ResourceUtil(){
        throw new IllegalStateException("Utility class");
    }

    public static Resource[] mapperLocations(String[] mapperLocations) {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList<>();
        if (mapperLocations != null) {
            for (String mapperLocation : mapperLocations) {
                try {
                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
                    resources.addAll(Arrays.asList(mappers));
                }
                catch (IOException e) {
                    // ignore
                    log.error("MapperLocations resolver failed, mapperLocations:{}, error:{}", mapperLocation, e);
                }
            }
        }
        return resources.toArray(new Resource[resources.size()]);
    }
}
上一篇:vuex


下一篇:16.LeetCode 最接近的三个数之和