SpringBoot 配置多數據源

1,負載均衡和主從同步配置

可以通過mysql的協議配置支持,不在本文探討範圍。配置方式如下

jdbcUrl: jdbc:mysql:replication://host1:port1,host2:port2/dbname?useSSL=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=true&serverTimezone=GMT%2B8

2,分庫分表等類的多數據源配置,不在本文探討範圍。

3,其他使用多個不同業務數據源配置步驟如下:

數據庫連接池以c3p0爲例,並且啓用了手動式事務管理。

3.1,配置數據庫連接池類型

spring: 
  datasource: 
    # 使用c3p0數據庫連接池
    type: com.mchange.v2.c3p0.ComboPooledDataSource

3.2,不使用系統默認數據庫配置,手動配置兩個數據源

# 數據源配置
datasource: 
  master: 
    driverClass: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql:replication://localhost:3306/goods?useSSL=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=true&serverTimezone=GMT%2B8
    user: demotest
    password: demotest
    minPoolSize: 4
    maxPoolSize: 20
    maxIdleTime: 1800000
    acquireIncrement: 2
    maxStatements: 0
    initialPoolSize: 4
    idleConnectionTestPeriod: 60
    acquireRetryAttempts: 5
    acquireRetryDelay: 1000
    breakAfterAcquireFailure: false
    testConnectionOnCheckin: true
    testConnectionOnCheckout: false
    preferredTestQuery: SELECT 1 FROM DUAL
  second: 
    driverClass: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql:replication://localhost:3306/users?useSSL=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    user: usertest
    password: usertest
    minPoolSize: 4
    maxPoolSize: 20
    maxIdleTime: 1800000
    acquireIncrement: 2
    maxStatements: 0
    initialPoolSize: 4
    idleConnectionTestPeriod: 60
    acquireRetryAttempts: 5
    acquireRetryDelay: 1000
    breakAfterAcquireFailure: false
    testConnectionOnCheckin: true
    testConnectionOnCheckout: false
    preferredTestQuery: SELECT 1 FROM DUAL

3.3,配置兩套MyBatis屬性

# mybatis配置
mybatis: 
  master:
    config-location: classpath:bean/mybatis/master/mybatis_config.xml
    mapper-locations: classpath:/bean/mybatis/master/mapping/*.xml
    type-aliases-package: com.beyonds.phoenix.demo.domain.dao.master.po
    type-dao-package: com.beyonds.phoenix.demo.domain.dao.master
    executorType: REUSE
  second: 
    config-location: classpath:bean/mybatis/second/mybatis_config.xml
    mapper-locations: classpath:/bean/mybatis/second/mapping/*.xml
    type-aliases-package: com.beyonds.phoenix.demo.domain.dao.second.po
    type-dao-package: com.beyonds.phoenix.demo.domain.dao.second
    executorType: REUSE

3.4,配置第一個數據源config文件

@Configuration
@MapperScan(basePackages = {"${mybatis.type-dao-package:com.beyonds.phoenix.demo.domain.dao.master}"}, 
            sqlSessionFactoryRef = "sqlSessionFactory")  
@EnableTransactionManagement
@ConditionalOnMissingBean({DataSourceConfiguration.class})
@AutoConfigureOrder(-100)
@AutoConfigureAfter({MybatisAutoConfiguration.class})
public class DatasourceConfig {
    protected static Logger logger = LoggerFactory.getLogger("DAO.LOG");
    
    @Value("${spring.datasource.type}")
    private Class<? extends DataSource> datasourceType;
    
    /**
     * 定義服務模板
     * @param transactionTemplate 事務模板
     * @return 服務模板
     */
    @Bean(name = "wdServiceTemplate")
    public WdServiceTemplateImpl wdServiceTemplate(
            @Qualifier("transactionTemplate") TransactionTemplate transactionTemplate) {
        return new WdServiceTemplateImpl(transactionTemplate);
    }
    
    /**
     * 定義主數據源
     * @return 主數據源
     */
    @Bean(name = "dataSource", destroyMethod = "close")
    @Primary
    @ConfigurationProperties(prefix = "datasource.master")
    public DataSource dataSource() {
        return DataSourceBuilder.create().type(datasourceType).build();
    }
    
    /**
     * 定義事務管理器
     * @param dataSource 數據源
     * @return 事務管理器
     */
    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    /**
     * 定義事務模板
     * @param transactionManager 事務管理器
     * @return 事務模板
     * @throws Exception 異常
     */
    @Bean(name = "transactionTemplate")
    public TransactionTemplate transactionTemplate(
            @Qualifier("transactionManager") DataSourceTransactionManager transactionManager) 
                    throws Exception {
        DefaultTransactionDefinition defaultTransactionDefinition = 
                new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
        defaultTransactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
        defaultTransactionDefinition.setTimeout(60); // 秒鐘
        
        return new TransactionTemplate(transactionManager, defaultTransactionDefinition);
    }
    
    /**
     * +自定義數據源配置
     * @param dataSource dataSource
     * @param properties properties
     * @param resourceLoader resourceLoader
     * @param interceptorsProvider interceptorsProvider
     * @param databaseIdProviderContainer databaseIdProviderContainer
     * @param configurationCustomizersProvider configurationCustomizersProvider
     * @return configurationCustomizersProvider
     * @throws Exception Exception
     */
    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(
            @Qualifier("dataSource") DataSource dataSource,
            @Qualifier("mybatisPropertiesMaster") MybatisProperties properties,
            ResourceLoader resourceLoader,
            ObjectProvider<Interceptor[]> interceptorsProvider,
            ObjectProvider<DatabaseIdProvider> databaseIdProviderContainer,
            ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider
            ) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(properties.getConfigLocation())) {
          factory.setConfigLocation(resourceLoader.getResource(properties.getConfigLocation()));
        }
        org.apache.ibatis.session.Configuration configuration = properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(properties.getConfigLocation())) {
          configuration = new org.apache.ibatis.session.Configuration();
        }
        List<ConfigurationCustomizer> configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
        if (configuration != null && !CollectionUtils.isEmpty(configurationCustomizers)) {
          for (ConfigurationCustomizer customizer : configurationCustomizers) {
            customizer.customize(configuration);
          }
        }
        factory.setConfiguration(configuration);
        if (properties.getConfigurationProperties() != null) {
          factory.setConfigurationProperties(properties.getConfigurationProperties());
        }
        Interceptor[] interceptors = interceptorsProvider.getIfAvailable();
        if (!ObjectUtils.isEmpty(interceptors)) {
          factory.setPlugins(interceptors);
        }
        DatabaseIdProvider databaseIdProvider = databaseIdProviderContainer.getIfAvailable();
        if (databaseIdProvider != null) {
          factory.setDatabaseIdProvider(databaseIdProvider);
        }
        if (StringUtils.hasLength(properties.getTypeAliasesPackage())) {
          factory.setTypeAliasesPackage(properties.getTypeAliasesPackage());
        }
        if (StringUtils.hasLength(properties.getTypeHandlersPackage())) {
          factory.setTypeHandlersPackage(properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(properties.resolveMapperLocations())) {
          factory.setMapperLocations(properties.resolveMapperLocations());
        }

        return factory.getObject();
    }
    
    /**
     * +定義配置文件
     * @return MybatisProperties
     */
    @Bean(name = "mybatisPropertiesMaster")
    @ConfigurationProperties(prefix = "mybatis.master")
    public MybatisProperties mybatisProperties() {
        return new MybatisProperties();
    }
}

3.5,配置第二個數據源config文件

@Configuration
@MapperScan(basePackages = {"${mybatis.type-dao-package:com.beyonds.phoenix.demo.domain.dao.second}"}, 
            sqlSessionFactoryRef = "sqlSessionFactorySecond")  
@EnableTransactionManagement
@ConditionalOnMissingBean({DataSourceConfiguration.class})
@AutoConfigureOrder(-90)
@AutoConfigureAfter({MybatisAutoConfiguration.class})
public class DatasourceSecondConfig {
    protected static Logger logger = LoggerFactory.getLogger("DAO.LOG");
    
    @Value("${spring.datasource.type}")
    private Class<? extends DataSource> datasourceType;
    
    /**
     * 定義服務模板
     * @param transactionTemplate 事務模板
     * @return 服務模板
     */
    @Bean(name = "wdServiceTemplateSecond")
    public WdServiceTemplateImpl wdServiceTemplateSecond(
            @Qualifier("transactionTemplateSecond") TransactionTemplate transactionTemplate) {
        return new WdServiceTemplateImpl(transactionTemplate);
    }
    
    /**
     * 定義主數據源
     * @return 主數據源
     */
    @Bean(name = "dataSourceSecond", destroyMethod = "close")
    @ConfigurationProperties(prefix = "datasource.second")
    public DataSource dataSourceSecond() {
        return DataSourceBuilder.create().type(datasourceType).build();
    }
    
    /**
     * 定義事務管理器
     * @param dataSource 數據源
     * @return 事務管理器
     */
    @Bean(name = "transactionManagerSecond")
    public DataSourceTransactionManager transactionManager(@Qualifier("dataSourceSecond") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    /**
     * 定義事務模板
     * @param transactionManager 事務管理器
     * @return 事務模板
     * @throws Exception 異常
     */
    @Bean(name = "transactionTemplateSecond")
    public TransactionTemplate transactionTemplate(
            @Qualifier("transactionManagerSecond") DataSourceTransactionManager transactionManager) 
                    throws Exception {
        DefaultTransactionDefinition defaultTransactionDefinition = 
                new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
        defaultTransactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
        defaultTransactionDefinition.setTimeout(60); // 秒鐘
        
        return new TransactionTemplate(transactionManager, defaultTransactionDefinition);
    }
    
    /**
     * +自定義數據源配置
     * @param dataSource dataSource
     * @param properties properties
     * @param resourceLoader resourceLoader
     * @param interceptorsProvider interceptorsProvider
     * @param databaseIdProviderContainer databaseIdProviderContainer
     * @param configurationCustomizersProvider configurationCustomizersProvider
     * @return configurationCustomizersProvider
     * @throws Exception Exception
     */
    @Bean(name = "sqlSessionFactorySecond")
    public SqlSessionFactory sqlSessionFactory(
            @Qualifier("dataSourceSecond") DataSource dataSource,
            @Qualifier("mybatisPropertiesSecond") MybatisProperties properties,
            ResourceLoader resourceLoader,
            ObjectProvider<Interceptor[]> interceptorsProvider,
            ObjectProvider<DatabaseIdProvider> databaseIdProviderContainer,
            ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider
            ) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(properties.getConfigLocation())) {
          factory.setConfigLocation(resourceLoader.getResource(properties.getConfigLocation()));
        }
        org.apache.ibatis.session.Configuration configuration = properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(properties.getConfigLocation())) {
          configuration = new org.apache.ibatis.session.Configuration();
        }
        List<ConfigurationCustomizer> configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
        if (configuration != null && !CollectionUtils.isEmpty(configurationCustomizers)) {
          for (ConfigurationCustomizer customizer : configurationCustomizers) {
            customizer.customize(configuration);
          }
        }
        factory.setConfiguration(configuration);
        if (properties.getConfigurationProperties() != null) {
          factory.setConfigurationProperties(properties.getConfigurationProperties());
        }
        Interceptor[] interceptors = interceptorsProvider.getIfAvailable();
        if (!ObjectUtils.isEmpty(interceptors)) {
          factory.setPlugins(interceptors);
        }
        DatabaseIdProvider databaseIdProvider = databaseIdProviderContainer.getIfAvailable();
        if (databaseIdProvider != null) {
          factory.setDatabaseIdProvider(databaseIdProvider);
        }
        if (StringUtils.hasLength(properties.getTypeAliasesPackage())) {
          factory.setTypeAliasesPackage(properties.getTypeAliasesPackage());
        }
        if (StringUtils.hasLength(properties.getTypeHandlersPackage())) {
          factory.setTypeHandlersPackage(properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(properties.resolveMapperLocations())) {
          factory.setMapperLocations(properties.resolveMapperLocations());
        }

        return factory.getObject();
    }
    
    /**
     * +定義配置文件
     * @return MybatisProperties
     */
    @Primary
    @Bean(name = "mybatisPropertiesSecond")
    @ConfigurationProperties(prefix = "mybatis.second")
    public MybatisProperties mybatisPropertiesSecond() {
        return new MybatisProperties();
    }
}

3.6,以上兩步定義了兩個不同的處理事務模板

@Bean(name = "wdServiceTemplate")
public WdServiceTemplateImpl wdServiceTemplate(
            @Qualifier("transactionTemplate") TransactionTemplate transactionTemplate) {
    return new WdServiceTemplateImpl(transactionTemplate);
}

@Bean(name = "wdServiceTemplateSecond")
public WdServiceTemplateImpl wdServiceTemplate(
            @Qualifier("transactionTemplateSecond") TransactionTemplate transactionTemplate) {
    return new WdServiceTemplateImpl(transactionTemplate);
}

可供程序根據不同的業務場景選擇使用不同的數據源。

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