一、概念:
Sharding-JDBC是一个在客户端的分库分表工具。它是一个轻量级Java框架,在Java的JDBC层提供的额外服务。
ShardingSphere提供标准化的数据分片、分布式事务和数据治理功能。
二、架构图:
- ShardingRuleConfiguration 可以包含多个 TableRuleConfiguration(多张表),也可以设置默认的分库和分表策略。
- 每个TableRuleConfiguration 可以针对表设置 ShardingStrategyConfiguration,包括分库分分表策略。
- ShardingStrategyConfiguration 有 5 种实现(标准、行内、复合、Hint、无)
- ShardingDataSourceFactory利用ShardingRuleConfiguration创建数据源。
三、基础概念:
逻辑表:
order_1、order_2、order_3
真实表:
order
数据节点:
数据分片的最小物理单元。由数据源名称和数据表组成,例: ds_0.order_0
绑定表:
指分片规则一致的主表和子表。例如: order和 t_order
广播表:
指所有的分片数据源中都存在的表,例如,字典表
分片策略:
包含分片键和分片算法;
- 具体策略:
- 标准分片策略(StandardShardingStrategy):用于处理 BETWEEN AND, >, =,
- 复合分片策略(ComplexShardingStrategy):支持多分片键,提供对 SQL 语句中的 =, >, =,
- 行表达式分片策略(InlineShardingStrategy): t_user_$->{u_id % 8} 表示 t_user 表根据 u_id 模 8,而分成 8 张表,表名称为 t_user_0 到 t_user_7
- Hint分片策略(HintShardingStrategy):通过 Hint 指定分片值而非从 SQL 中提取分片值的方式进行分片的策略
- 不分片策略(NoneShardingStrategy)
- 分片键:用于分片的表字段
- 分片算法:
- 精确分片算法(单一分片键,例如 =、in)
- 范围分片算法(单一分片键,例如 ETWEEN AND、>、=、
- 复合分片算法(多片键)
- Hint分片算法
主键生成策略:
通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。
四、执行流程:
SQL 解析 => 查询优化 => SQL路由 => SQL改写 => SQL执行 => 结果归并
五、使用方法:
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# pom.xml
<!--sharding-jdbc-->
<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version>
</dependency>---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# 自定义分片规则,需要Java SPI进行加载。
/*** 〈一句话功能简述〉<br>* 〈客户端用户表id自增生成〉** @author hanxinghua* @create 2022/6/10* @since 1.0.0*/
@Component
public class AppUserIdGenerator implements ShardingKeyGenerator {private RedisUtil redisUtil;@Overridepublic Comparable<?> generateKey() {if (redisUtil == null) {synchronized (this) {if (redisUtil == null) {redisUtil = SpringUtil.getBean("redisUtil");}}}return redisUtil.incr(AppUtil.APP_USER_ID, 1L);}@Overridepublic String getType() {return "APPUSERID";}@Overridepublic Properties getProperties() {return null;}@Overridepublic void setProperties(Properties properties) {}
}
Java SPI 地址:
src/main/resources/META-INF/services/org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator
ShardingKeyGenerator内容:
com.hippo.online.config.shardingjdbc.AppUserIdGenerator---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# 自定义分片规则
/*** 〈一句话功能简述〉<br>* 〈用户表分片规则〉** @author hanxinghua* @create 2022/6/13* @since 1.0.0*/
public class AppUserShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {@Overridepublic String doSharding(Collection<String> targetTableNames, PreciseShardingValue<Integer> shardingValue) {String value = String.valueOf(shardingValue.getValue());for (String targetTableName : targetTableNames) {if (targetTableName.endsWith(value)) {return targetTableName;}}return "app_user_999";}
}
/*** 〈一句话功能简述〉<br>* 〈用户记录表分片规则〉** @author hanxinghua* @create 2022/6/13* @since 1.0.0*/
public class AppUserRecordShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {@Overridepublic String doSharding(Collection<String> targetTableNames, PreciseShardingValue<Integer> shardingValue) {String value = String.valueOf(shardingValue.getValue());for (String targetTableName : targetTableNames) {if (targetTableName.endsWith(value)) {return targetTableName;}}return "app_user_record_999";}
}---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# yaml配置:
spring:shardingsphere:# 数据源配置datasource:names: ds0ds0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driver... ... props:sql.show: true # 打开sql输出日志sharding:defaultDataSourceName: ds0 # 默认数据源名称tables:# 逻辑表名称app_user:# 数据节点:数据源$->{0..N}.逻辑表名$->{0..N}actualDataNodes: ds0.app_user_$->{999..1011} # 现在是只分表不分库# 主键生成规则keyGenerator:column: idtype: APPUSERID # 自定义# 拆分表策略tableStrategy:standard:shardingColumn: app_idpreciseAlgorithmClassName: com.config.shardingjdbc.AppUserShardingAlgorithm# 逻辑表名称 app_user_record:actualDataNodes: ds0.app_user_record_$->{999..1011} # 现在是只分表不分库tableStrategy:standard:shardingColumn: app_idpreciseAlgorithmClassName: com.config.shardingjdbc.AppUserRecordShardingAlgorithm# 绑定表bindingTables: app_user,app_user_record# 表达式举例:
## ${begin..end}:表示范围区间
## ${[unit1, unit2, unit_x]}:表示枚举值
## db1.table_$->{[1,2]}
## t_user_$->{u_id % 8}:表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7# 主键生成规则举例:
key-generator:column: idtype: SNOWFLAKE #雪花算法props:work.id: 0 # 表示雪花id机器标识位,取值范围[0,1024)max.vibration.offset: 2 # 在高并发下,每次生成id都可能跨毫秒,夸毫秒,则序列部分会从0开始计算,每次生成的id都是偶数,奇偶分片有问题# 用于单分片键的标准分片举例:
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.standard.sharding-column= #分片列名称
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.standard.precise-algorithm-class-name= #精确分片算法类名称,用于=和IN。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.standard.range-algorithm-class-name= #范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器# 用于多分片键的复合分片举例:
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.complex.sharding-columns= #分片列名称,多个列以逗号分隔
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.complex.algorithm-class-name= #复合分片算法类名称。该类需实现ComplexKeysShardingAlgorithm接口并提供无参数的构造器
六、多数据源配置:
# pom.xml:
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.2.1</version>
</dependency># 配置多数据源:
## 设置严格模式,默认false(不启动)。启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源。
spring.datasource.dynamic.strict=true
## 设置默认的数据源或者数据源组,默认值即为master
spring.datasource.dynamic.primary=master
## 配置master数据源:
### 以下datasource相关,省略部分
spring.datasource.dynamic.datasource.master.type=
spring.datasource.dynamic.datasource.master.driverClassName =... ...
## 配置shardingsphere相关数据源:
### 以下datasource相关,省略部分
spring.shardingsphere.datasource.names=ds-1
spring.shardingsphere.datasource.ds-1.type=
spring.shardingsphere.datasource.ds-1.driverClassName=... ...
spring.shardingsphere.datasource.names=ds-2
spring.shardingsphere.datasource.ds-2.type=
spring.shardingsphere.datasource.ds-2.driverClassName=... ...# 数据源配置类:
/*** 〈一句话功能简述〉<br>* 〈配置数据源〉** @author hanxinghua* @create 2022/6/16* @since 1.0.0*/
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DataSourceConfig {/*** 分表数据源名称*/public static final String SHARDING_DATA_SOURCE_NAME = "sharding";/*** 动态数据源配置项*/@Autowiredprivate DynamicDataSourceProperties dynamicDataSourceProperties;@Lazy@Resourceprivate DataSource shardingDataSource;@Beanpublic DynamicDataSourceProvider dynamicDataSourceProvider() {Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource();return new AbstractDataSourceProvider() {@Overridepublic Map<String, DataSource> loadDataSources() {Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);// 将Sharding-jdbc管理的数据源也交给动态数据源管理dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource);return dataSourceMap;}};}@Bean@Primarypublic DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());dataSource.setStrict(dynamicDataSourceProperties.getStrict());dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());dataSource.setProvider(dynamicDataSourceProvider);dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());dataSource.setSeata(dynamicDataSourceProperties.getSeata());return dataSource;}
}# 使用:访问没有分表的数据时使用默认的普通数据源,访问分表的数据时使用@DS("sharding")注解
七、数据迁移:
1.停机迁移(不推荐)
2.数据双写迁移
3.采用canal中间件迁移