依赖
XML
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
dynamic-datasource-spring-boot-starter 版本3.1.0 有BUG,异常情况下切换数据源会不成功,导致找不到表,所以使用 4.2.0
配置
Bash
spring.shardingsphere.sharding.default-data-source-name = ds
# 数据源配置
spring.shardingsphere.datasource.names = ds
# 数据源具体配置
spring.shardingsphere.datasource.ds.type = com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds.driver-class-name = com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds.jdbc-url = jdbc:mysql://xxxxxxxxxxxxxx:3306/aep?characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true
spring.shardingsphere.datasource.ds.username = root
spring.shardingsphere.datasource.ds.password = pppppppppppp
# 分表配置 - 表名称
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.actual-data-nodes = ds.aep_abtest_config_deploy_log_$->{2025..2035}0$->{1..9},ds.aep_abtest_config_deploy_log_$->{2025..2035}1$->{0..2}
# 分表策略 - 分片列
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.table-strategy.standard.sharding-column = create_time
# 分表策略 - 精确分片算法类
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.table-strategy.standard.precise-algorithm-class-name = com.transsnet.aep.configuration.MonthlyShardingAlgorithm
# 主键生成策略 - 列名
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.key-generator.column = id
# 主键生成策略 - 类型
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.key-generator.type = SNOWFLAKE
# 显示SQL
spring.shardingsphere.props.sql.show = true
# 是否开启ShardingSphere
spring.shardingsphere.enabled = true
# 数据源连接池配置
spring.shardingsphere.datasource.ds.connection-timeout = 30000
spring.shardingsphere.datasource.ds.idle-timeout = 600000
spring.shardingsphere.datasource.ds.max-lifetime = 1800000
spring.shardingsphere.datasource.ds.maximum-pool-size = 10
spring.shardingsphere.datasource.ds.minimum-idle = 5
spring.shardingsphere.datasource.ds.pool-name = HikariPool-ds
# 默认使用分片数据源
spring.datasource.dynamic.primary = sharding
spring.datasource.dynamic.datasource.ups.poolName = ups-pool
spring.datasource.dynamic.datasource.ups.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.ups.type = com.zaxxer.hikari.HikariDataSource
spring.datasource.dynamic.datasource.ups.url = jdbc:mysql://xxxxxxxxxxxxxx:3306/ups?characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true
spring.datasource.dynamic.datasource.ups.username = root
spring.datasource.dynamic.datasource.ups.password = pppppppppppp
spring.datasource.dynamic.datasource.dim.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.dim.poolName = dim-pool
spring.datasource.dynamic.datasource.dim.type = com.zaxxer.hikari.HikariDataSource
spring.datasource.dynamic.datasource.dim.url = jdbc:mysql://xxxxxxxxxxxxxx:3306/ups_dim?characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false
spring.datasource.dynamic.datasource.dim.username = root
spring.datasource.dynamic.datasource.dim.password = pppppppppppp
代码配置
DynamicDataSourceConfig
类是一个关键的数据源集成配置类,它负责将 ShardingSphere 的分片数据源与 dynamic-datasource 的多数据源动态路由功能进行整合。
核心目标:让 ShardingSphere 的分片数据源能够作为 dynamic-datasource 框架中的一个普通数据源来使用,实现分片数据源和非分片数据源的统一管理。
Java
package com.transsnet.aep.configuration;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DynamicDataSourceConfig {
@Resource
private DynamicDataSourceProperties properties;
/**
* 未使用分片, 脱敏的名称(默认): shardingDataSource
* shardingjdbc使用了主从: masterSlaveDataSource
* 此处如果主从策略配置在sharding属性下面,需要使用shardingDataSource
*/
@Lazy
@Resource(name = "shardingDataSource")
private DataSource shardingDataSource;
@Resource
private DefaultDataSourceCreator dataSourceCreator;
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
return new AbstractDataSourceProvider(dataSourceCreator) {
@Override
public Map<String, DataSource> loadDataSources() {
// 先创建动态数据源
Map<String, DataSource> dataSourceMap = createDataSourceMap(properties.getDatasource());
// 确保动态数据源不为空
if (dataSourceMap.isEmpty()) {
dataSourceMap = Maps.newHashMap();
}
// 将ShardingSphere数据源添加到动态数据源集合中
dataSourceMap.put("sharding", shardingDataSource);
return dataSourceMap;
}
};
}
/**
* 将动态数据源设置为首选的
* 当spring存在多个数据源时, 自动注入的是首选的对象
* 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
*/
@Primary
@Bean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
List<DynamicDataSourceProvider> providers = Lists.newArrayList(dynamicDataSourceProvider);
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers);
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
}
这个 DynamicDataSourceConfig
类是一个桥梁类,它:
-
集成:将 ShardingSphere 的分片能力集成到 dynamic-datasource 框架中
-
统一:提供统一的数据源访问接口
-
隔离:确保分片数据源和非分片数据源相互隔离
-
灵活:支持通过注解动态切换数据源
启动类
TypeScript
@ComponentScan(basePackages = {"com.transsnet"})
@MapperScan(basePackages = {"com.transsnet.aep.mapper"})
// 防止Spring Boot的自动配置与ShardingSphere、dynamic-datasource的配置发生冲突
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourcePoolMetricsAutoConfiguration.class
})
public class AepWebApplication {
public static void main(String[] args) {
SpringApplication.run(AepWebApplication.class, args);
}
}
启动类中排除这些自动配置类是为了防止Spring Boot的自动配置与ShardingSphere、dynamic-datasource的配置发生冲突。让我详细解释每个排除项的作用:
1. DataSourceAutoConfiguration.class
为什么要排除:
java
exclude = DataSourceAutoConfiguration.class
作用:
-
防止自动创建数据源:Spring Boot会自动根据
spring.datasource.*
配置创建默认数据源 -
避免配置冲突:我们使用ShardingSphere和dynamic-datasource来管理数据源,不需要Spring Boot的自动配置
-
防止Bean重复:避免创建多个相同类型的数据源Bean导致冲突
如果不排除:
Spring Boot会尝试根据以下配置创建数据源:
properties
spring.datasource.url=...spring.datasource.username=...spring.datasource.password=...
这与我们手动配置的ShardingSphere数据源冲突。
2. DataSourcePoolMetricsAutoConfiguration.class
为什么要排除:
java
exclude = DataSourcePoolMetricsAutoConfiguration.class
作用:
-
避免监控指标冲突:这个自动配置会为数据源创建监控指标
-
防止Bean依赖问题:它期望找到Spring Boot自动创建的数据源,但我们使用的是自定义数据源
-
指标重复:ShardingSphere和dynamic-datasource可能有自己的监控机制
总结
1. 数据源隔离
-
分片数据源和非分片数据源完全隔离
-
避免分片逻辑影响到普通业务表
2. 统一管理
-
通过统一的
@DS
注解来切换数据源 -
简化代码,提高可维护性
3. 灵活扩展
-
可以轻松添加新的数据源
-
分片和非分片数据源可以独立演进