一、分库分表
需求分析:
- 创建数据库 sharding_db1和sharding_db1
- 在数据库创建两张表 course_1 和 course_2
- 数据库规则:如果课程 id 是偶数,则添加 sharding_db1库,如果是奇数添加到 sharding_db2库。
- 数据表规则:如果课程 id 是偶数,则添加 course_1表,如果是奇数添加到 course_2表。
1、application.properties 配置文件
在项目 application.properties 配置文件中进行配置。
# 配置真实数据源
spring.shardingsphere.datasource.names=db1,db2
# 配置第1个数据源
spring.shardingsphere.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db1.url=jdbc:mysql://localhost:3306/sharding_db1?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT
spring.shardingsphere.datasource.db1.username=root
spring.shardingsphere.datasource.db1.password=123456
# 配置第2个数据源
spring.shardingsphere.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db2.url=jdbc:mysql://localhost:3306/sharding_db2?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT
spring.shardingsphere.datasource.db2.username=root
spring.shardingsphere.datasource.db2.password=123456
# 指定库表的分布情况:分库,分表
spring.shardingsphere.sharding.tables.course.actual-data-nodes=db$->{1..2}.course_$->{1..2}
# 指定表的主键生成策略,雪花算法
spring.shardingsphere.sharding.tables.course.key-generator.column=id
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1
#指定分片策略
#1. inline分片策略
#1.1 库策略
spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=db$->{id%2+1}
#1.2 表策略
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{id%2+1}
# 打开shardingsphere的sql日志输出。
spring.shardingsphere.props.sql.show=true
# 一个实体类对应两张表,覆盖
spring.main.allow-bean-definition-overriding=true
2、测试代码
1)保存
@Test
public void testSave() throws InterruptedException {
for (int i = 0; i < 20; i++) {
Course course = new Course();
course.setGmtCreate(new Date());
course.setName("java");
course.setUserId(1001L + i);
course.setStatus("1");
TimeUnit.MILLISECONDS.sleep(50);
int count = courseMapper.insert(course);
System.out.println("id ->" + course.getId());
}
}
数据按照我们的分库分表规则落库ok。
二、分片策略
目前提供5种分片策略:
- 行表达式分片策略,对应InlineShardingStrategy。
- 标准分片策略,对应StandardShardingStrategy。
- 复合分片策略,对应ComplexShardingStrategy。
- Hint分片策略,对应HintShardingStrategy。
- 不分片策略,对应NoneShardingStrategy。
1、行表达式分片策略
对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用。
1)在 application.properties 配置文件中进行配置。
#1. inline分片策略
#1.1 库策略
spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=db$->{id%2+1}
#1.2 表策略
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{id%2+1}
2、标准分片策略
对应StandardShardingStrategy。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。
1)在 application.properties 配置文件中进行配置
#2. standard标准分片策略: in eq between
#2.1 库策略
spring.shardingsphere.sharding.tables.course.table-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.course.table-strategy.standard.precise-algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.standard.MyPreciseTableShardingAlgorithm
spring.shardingsphere.sharding.tables.course.table-strategy.standard.range-algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.standard.MyRangeTableShardingAlgorithm
##2.2 库策略
spring.shardingsphere.sharding.tables.course.database-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.course.database-strategy.standard.precise-algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.standard.MyPreciseDSShardingAlgorithm
spring.shardingsphere.sharding.tables.course.database-strategy.standard.range-algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.standard.MyRangeDSShardingAlgorithm
库与表的分片策略需要我们自定义。
2)库策略算法
/**
* 自定义扩展的精确分片算法
*/
public class MyPreciseDSShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
/**
* @param availableTargetNames 有效的数据源或表的名字。对应配置文件中配置的数据源信息
* @param shardingValue 包含 逻辑表名、分片列和分片列的值。
* @return 返回目标结果
*/
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
//实现db$->{id%2+1} 分库策略
BigInteger shardingValueB = BigInteger.valueOf(shardingValue.getValue());
BigInteger resB = (shardingValueB.mod(new BigInteger("2"))).add(new BigInteger("1"));
String key = "db"+resB ;
if(availableTargetNames.contains(key)){
return key;
}
throw new UnsupportedOperationException(" route "+key+" is not supported. please check your config");
}
}
/**
* 自定义扩展的范围分片算法。
*/
public class MyRangeDSShardingAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
return availableTargetNames;
}
}
3)表策略算法
public class MyPreciseTableShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
//实现按照 = 或 IN 进行精确分片。
//例如 select * from course where id = 1 or id in (1,3,5)
//实现course_$->{cid%2+1} 分表策略
BigInteger shardingValueB = BigInteger.valueOf(shardingValue.getValue());
BigInteger resB = shardingValueB.mod(new BigInteger("2"))
.add(new BigInteger("1"));
String key = shardingValue.getLogicTableName()+"_"+resB ;
if(availableTargetNames.contains(key)){
return key;
}
throw new UnsupportedOperationException(" route "+key+" is not supported. please check your config");
}
}
public class MyRangeTableShardingAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
//实现按照 Between 进行范围分片。
//例如 select * from course where id between 2000 and 3000;
Long lowerEndpoint = shardingValue.getValueRange().lowerEndpoint();//2000
Long upperEndpoint = shardingValue.getValueRange().upperEndpoint();//3000
//实现course_$->{(3000 -2000 )%2+1} 分片策略
// return Arrays.asList(shardingValue.getLogicTableName()+"_"+shardingValue.getLogicTableName() + ((upperEndpoint - lowerEndpoint) % 2 + 1));
//对于我们这个奇偶分离的场景,大部分范围查询都是要两张表都查。
return Arrays.asList(shardingValue.getLogicTableName()+"_1",shardingValue.getLogicTableName()+"_2");
}
}
4)测试查询
3、复合分片策略
对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
1)在 application.properties 配置文件中进行配置
#3. complex复杂分片策略:复杂查询
##3.1 库策略
spring.shardingsphere.sharding.tables.course.table-strategy.complex.sharding-columns= cid, user_id
spring.shardingsphere.sharding.tables.course.table-strategy.complex.algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.complex.MyComplexTableShardingAlgorithm
##3.2 库策略
spring.shardingsphere.sharding.tables.course.database-strategy.complex.sharding-columns=cid, user_id
spring.shardingsphere.sharding.tables.course.database-strategy.complex.algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.complex.MyComplexDSShardingAlgorithm
2)策略算法
public class MyComplexDSShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
/**
*
* @param availableTargetNames 目标数据源 或者 表 的值。
* @param shardingValue logicTableName逻辑表名 columnNameAndShardingValuesMap 分片列的精确值集合。 columnNameAndRangeValuesMap 分片列的范围值集合
* @return
*/
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
return availableTargetNames;
}
}
public class MyComplexTableShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
//实现按照 Between 进行范围分片。
//例如 select * from course where id in (1,3,5) and user_id Between 200 and 300;
Collection<Long> cidCol = shardingValue.getColumnNameAndShardingValuesMap().get("id");
Range<Long> uageRange = shardingValue.getColumnNameAndRangeValuesMap().get("user_id");
List<String> result = new ArrayList<>();
Long lowerEndpoint = uageRange.lowerEndpoint();//200
Long upperEndpoint = uageRange.upperEndpoint();//300
//实现自定义分片逻辑 例如可以自己实现 course_$->{cid%2+1}
for(Long id : cidCol){
BigInteger idI = BigInteger.valueOf(id);
BigInteger target = (idI.mod(BigInteger.valueOf(2L))).add(new BigInteger("1"));
result.add("course_"+target);
}
return result;
}
}
4、Hint分片策略
对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。
注意使用它时有非常多的限制。
1)在 application.properties 配置文件中进行配置
#4. hint强制路由策略:与sql无关
##4.1 库策略
spring.shardingsphere.sharding.tables.course.table-strategy.hint.algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.hint.MyHintTableShardingAlgorithm
##4.2 库策略
spring.shardingsphere.sharding.tables.course.database-strategy.hint.algorithm-class-name=com.charge.learn.shardingsphere.jdbc.study.sharding.strategy.hint.MyHintTableShardingAlgorithm
2)策略算法
public class MyHintDSShardingAlgorithm implements HintShardingAlgorithm<Integer> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Integer> shardingValue) {
return Arrays.asList("db1","db2");
}
}
public class MyHintTableShardingAlgorithm implements HintShardingAlgorithm<Integer> {
/**
*
* @param availableTargetNames 可选 数据源 和 表 的名称
* @param shardingValue
* @return
*/
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Integer> shardingValue) {
// 对SQL的零侵入分片方案。shardingValue是通过HintManager.
// 比如我们要实现将 select * from t_user where user_id in {1,2,3,4,5,.....}; 按照in的第一个值,全部路由到course_1表中。
String key = "course_"+shardingValue.getValues().toArray()[0];
if(availableTargetNames.contains(key)){
return Arrays.asList(key);
}
// return Arrays.asList("course_1");
throw new UnsupportedOperationException(" route "+key+" is not supported. please check your config");
}
}
分片策略,有时是针对sql定制的,所以在使用过程中有一定的限制。
参见官网文档: https://shardingsphere.apache.org/document/current/cn/features/sharding/use-norms/sql/
参考文章:
- ShardingSphere官方网址:https://shardingsphere.apache.org/document/current/cn/overview/
- ShardingSphere基本介绍及核心概念:https://blog.csdn.net/Kiven_ch/article/details/119087048
– 求知若饥,虚心若愚。