前些天,领导在群里发了一份 Sharding-JDBC 的技术文档,要求笔者写一份 分表扩容方案。
要求:使用 Sharding-JDBC 进行分表,不分库,ID 自增,按照每张表放 1000 万数据,扩容 4 张表。
笔者在网上找啊找,发现 Sharding-JDBC 是 2017 年的项目,距今 7 年历史,相关文档居然不全!
出于对官方文档的失望,也不知道是不是最新版本有冲突,又或者不同版本配置差别比较大。
笔者只能一边找,一边试~,最终弄出来了。
水平分表步骤
- 对表 A、表 B 进行水平扩展,当前暂定额外扩展数4。
- 按照“{表名}_{扩展数}” 创建数据表名,改名为{表名}_0。
- 移除原表ID自增,使用ID主键自增方案,手动设置记录ID,相同表名ID自增保持同步。
- 约定规则:
- 原表table_0存放ID为 [ 0~2000 万) 的记录,若原表超过2000万,则以原表总数为上限。
- 以此类推table_1存放 [ 1000万~2000万 )。
- 最后一张表table_4 存放 [ 5000万~ 最大值)。
项目环境,POM 文件
● java1.8
● Springboot2.0.6.RELEASE
● MybatisPlus3.1.2
● ShardingSphere-JDBC 4.0.0-RC1
● Druid 连接池
POM 文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<mybatis-spring-boot>3.1.2</mybatis-spring-boot>
<druid>1.1.16</druid>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 最新版本的 Mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-spring-boot}</version>
</dependency>
<!--mybatis驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid}</version>
</dependency>
<!--shardingsphere最新版本-->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>4.0.0-RC1</version>
</dependency>
<!--lombok实体工具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Bean、Mapper、SQL
● Bean 和 Mapper 使用 Mybatis plus 默认的配置即可,需要注意的是:主键用自增
● SQL 主键按照设计即可
Application.properties配置文件
server.port=8088
spring.shardingsphere.datasource.names=master
# 数据源 主库
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.url=jdbc:mysql://10.xx.7.xxx:4000/test?characterEncoding=utf-8&allowMultiQueries=true
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=
#数据分表规则
#所需分的表tableA
spring.shardingsphere.sharding.tables.document.actual-data-nodes=master.tableA$->{0..4}
#指定主键
spring.shardingsphere.sharding.tables.document.table-strategy.standard.sharding-column=id
#分表规则
spring.shardingsphere.sharding.tables.document.table-strategy.standard.precise-algorithm-class-name=com.aspire.ssdoc.config.RangePreciseSharding
spring.shardingsphere.sharding.tables.document.table-strategy.standard.range-algorithm-class-name=com.aspire.ssdoc.config.RangeSharding
#所需分的表tableB
spring.shardingsphere.sharding.tables.individual.actual-data-nodes=master.tableB_$->{0..4}
#指定主键
spring.shardingsphere.sharding.tables.individual.table-strategy.standard.sharding-column=pes_id
#分表规则
spring.shardingsphere.sharding.tables.individual.table-strategy.standard.precise-algorithm-class-name=com.aspire.ssdoc.config.RangePreciseSharding
spring.shardingsphere.sharding.tables.individual.table-strategy.standard.range-algorithm-class-name=com.aspire.ssdoc.config.RangeSharding
#打印sql
spring.shardingsphere.props.sql.show=true
分片配置类
注意,这是分片配置对象,需要在Application.properties,分表规则里配置它的类路径名
value 变量代表 id,返回的 logicTableName 则是记录最终储存的表名
例如:
spring.shardingsphere.sharding.tables.document.table-strategy.standard.sharding-column=id
#分表规则
spring.shardingsphere.sharding.tables.document.table-strategy.standard.precise-algorithm-class-name=com.xxx.xxx.config.RangePreciseSharding
public class RangePreciseSharding implements PreciseShardingAlgorithm<Integer> {
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) {
Integer value = preciseShardingValue.getValue();
String logicTableName = preciseShardingValue.getLogicTableName();
// 后缀
int tabIndex;
if (value < 20_000_000 ){
tabIndex = 0;
}else if (value >= 50_000_000){
tabIndex = 4;
}else {
tabIndex = value / 10_000_000 - 1;
}
String newTableName = logicTableName + "_" + tabIndex;
System.out.println("newTableName " + newTableName);
return newTableName;
}
}
范围查询配置类
不配也没关系,默认配所有的表查询
笔者这里配了所有表名,其实就是默认配置。
public class RangeSharding implements RangeShardingAlgorithm<Integer> {
@Override
public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Integer> rangeShardingValue) {
String logicTableName = rangeShardingValue.getLogicTableName();
return Arrays.asList(logicTableName + "_0", logicTableName + "_1", logicTableName + "_2");
}
}
说明
● 笔者这里领导要求,ID 是自增长,且按表顺序储存的。因为这部分业务曾经有经过扩容,估计后续还会扩容,所以需要按顺序储存。
● 笔者这里的 ID 是从“自增长 ID 生成器”里获取,然后手动 set 进去的,因为如果让表自增的话,会出现重复的 ID。
● 如果不需要自增 ID,可以将其设定为“雪花算法”,然后通过取余,将记录均匀分布到各个表。具体操作可参阅其它资料