欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > ShardingSphere初探

ShardingSphere初探

2024/10/24 18:25:31 来源:https://blog.csdn.net/aoxiaojun/article/details/140028890  浏览:    关键词:ShardingSphere初探

ShardingSphere初探

文章目录

    • ShardingSphere初探
      • ShardingSphere
        • 主要组件
        • 核心功能
        • 优点
        • Sharding-JDBC和Sharding-proxy的对比
      • Sharding-jdbc水平分表演示
        • 水平分表
        • 逻辑表和物理表划分
        • 分片键和分片算法的选取
        • Sharding-jdbc 基于SpringBoot演示
      • Sharding-jdbc水平分库分表演示
      • 查询演示
      • 范围查询
      • 标准策略的定制
      • 复合策略的定制
      • hint策略的定制

ShardingSphere

ShardingSphere 是一个分布式数据库中间件生态系统,旨在解决数据库的分布式架构问题。它提供了数据分片、读写分离、弹性缩容、分布式事务、数据加密等功能,帮助企业构建高性能、可扩展的分布式数据库解决方案。 由 Apache 软件基金会孵化和维护,是一个开源项目。

主要组件
  1. Sharding-JDBC
    • 是一个轻量级的 Java 框架,嵌入在应用程序中,提供 JDBC 连接池和 SQL 解析、改写、执行等功能。它通过在应用层实现分片逻辑,支持各种关系数据库。
  2. Sharding-Proxy
    • 是一个独立的代理层,支持任何兼容 MySQL、PostgreSQL 协议的客户端。它拦截 SQL 请求,执行分片、读写分离等操作,返回聚合结果给客户端。
  3. Sharding-Sidecar(又称 Sharding-Sphere on Kubernetes)
    • 是针对 Kubernetes 环境设计的微服务解决方案,通过 Sidecar 模式实现数据库的分片和读写分离,适用于云原生应用。
核心功能
  1. 数据分片(Sharding)
    • 通过水平分表和分库的方式,将数据分散存储到多个数据库实例中,提升系统的扩展性和性能。
  2. 读写分离
    • 通过主从复制,实现读写请求的分离,减轻主数据库的压力,提高读操作的性能。
  3. 分布式事务
    • 支持 XA、BASE 等分布式事务协议,确保在分布式环境中的数据一致性。
  4. 弹性缩容
    • 支持在线添加或删除数据库节点,动态调整分片规则,实现系统的弹性扩展和收缩。
  5. 数据加密
    • 提供数据加密功能,确保存储数据的安全性。
优点
  • 开源和社区支持:ShardingSphere 是 Apache 基金会的顶级项目,拥有活跃的社区和丰富的文档资源。
  • 灵活性:支持多种数据库,兼容性好,易于与现有系统集成。
  • 高性能:通过分片和读写分离,提高了数据库的并发处理能力。
  • 易扩展:弹性缩容功能使系统能应对动态变化的业务需求。

ShardingSphere 适用于需要高可用性、高性能和高扩展性的分布式数据库应用场景,如互联网、电商、金融等行业。

Sharding-JDBC和Sharding-proxy的对比
特性Sharding-JDBCSharding-Proxy
架构类型嵌入式代理层
部署位置应用程序内部独立部署于服务器之间
适用语言Java支持任何兼容 MySQL、PostgreSQL 协议的客户端
性能高(无网络开销)取决于网络延迟和代理层性能
透明性对应用程序透明,需少量配置对客户端透明,只需配置代理地址
支持的数据库MySQL, PostgreSQL, Oracle, SQL Server, 等MySQL, PostgreSQL
读写分离支持支持
数据分片支持支持
分布式事务支持支持
兼容性与 ORM 框架(如 Hibernate、MyBatis)无缝集成兼容所有符合协议的客户端
部署和运维需要在每个应用程序中部署和配置集中管理,简化了客户端的部署
扩展性取决于应用程序的扩展性容易通过增加代理节点来扩展
复杂性应用程序内增加复杂性,需要修改和配置应用程序中心化配置,减少应用程序的复杂性
适用场景小型到中型系统,单体应用大型系统,微服务架构,需支持多种语言的环境
  • Sharding-JDBC 更适合需要高性能和对数据库操作有精细控制的小型到中型 Java 应用程序

  • Sharding-Proxy 更适合需要语言无关的解决方案的大型系统或微服务架构。

Sharding-jdbc水平分表演示

水平分表
  • 概念:将一个大表的数据按照某种规则(如根据用户ID)分成多个小表,每个小表包含一部分数据。
  • 优点:减小了单表的大小,提升了查询和写入性能。
  • 缺点:需要处理跨表查询和数据的均衡分布问题。

假如我们现在有个逻辑表course,详细的sql如下

CREATE TABLE `course` (`cid` bigint NOT NULL AUTO_INCREMENT,`cname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,`user_id` bigint DEFAULT NULL,`cstatus` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=1012831258863996929 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;RSET=utf8mb4 COLLATE=utf8mb4_general_ci;
逻辑表和物理表划分

此时由于业务需要,需要将course表水平拆分。具体拆分规则如下,将course表拆分成course_1course_2。此时course_1和course_2为物理表,实际储存数据的表。

相应的表sql如下,只是表名不同,字段完全一样,创建好这两张表

CREATE TABLE `course_1` (`cid` bigint NOT NULL AUTO_INCREMENT,`cname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,`user_id` bigint DEFAULT NULL,`cstatus` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=1012831258863996929 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;RSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `course_2` (`cid` bigint NOT NULL AUTO_INCREMENT,`cname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,`user_id` bigint DEFAULT NULL,`cstatus` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=1012831258863996929 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;RSET=utf8mb4 COLLATE=utf8mb4_general_ci;
分片键和分片算法的选取

由于cid的唯一性,可以采用雪花算法生成cid,并可利用哈希算法对cid取模操作,均匀分配到每个数据分片上面

对应的分片算法为 shard = (cid % 2 + 1)

Sharding-jdbc 基于SpringBoot演示
  1. 创建sharding-demo-1的SpringBoot项目,并引入以下依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.23</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.2</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency>
</dependencies>
  1. 创建entity表Course
public class Course {private Long cid;private String cname;@TableField("user_id")private Long userid;private String cstatus;...getter setter toString}
  1. 创建CourseMapper
@Mapper
public interface CourseMapper extends BaseMapper<Course> {}
  1. 配置sharding-jdbc相关参数
spring:shardingsphere:datasource:#配置第一个数据源m1names: m1#配置第一个数据源m1的详细信息m1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.56.102:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: 123456#配置分片表的详细信息sharding:tables:#配置逻辑表course的主键生成规则和详细的分片策略course:#配置逻辑表和物理表之间的关系,此时将course分成course_1和course_2actual-data-nodes: m1.course_$->{1..2}# 配置主键生成规则key-generator:column: cidtype: SNOWFLAKEprops:worker:id: 1table-strategy:inline:# 配置分片键sharding-column: cid#配置分片算法algorithm-expression: course_$->{cid % 2 + 1}props:sql:#开启sp  sql日志show: true
  1. 创建ShardingTest测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class ShardingTest {@Resourceprivate CourseMapper courseMapper;@Testpublic void addCourse(){for (int i = 0; i < 10; i++) {Course course = new Course();course.setCname("c++");course.setUserid(180L);course.setCstatus("2");courseMapper.insert(course);}}@Testpublic void findCourse(){QueryWrapper<Course> objectQueryWrapper = new QueryWrapper<>();List<Course> courses = courseMapper.selectList(objectQueryWrapper);System.out.println(courses.size());}
}

运行addCourse(),观察数据库中是否插入数据

course_1内容如下:

cidcnameuser_idcstatus
1012880134358700032c++1802
1012880134933319680c++1802
1012880135017205760c++1802
1012880135096897536c++1802
1012880135159812096c++1802

course_2内容如下:

cidcnameuser_idcstatus
1012880134887182337c++1802
1012880134979457025c++1802
1012880135046565889c++1802
1012880135130451969c++1802
1012880135180783617c++1802

查看console台日志

2024-06-27 00:24:02.517  INFO 24260 --- [           main] ShardingSphere-SQL                       : SQLStatement: InsertStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@e91af20, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@6221b13b), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@6221b13b, columnNames=[cname, user_id, cstatus], insertValueContexts=[InsertValueContext(parametersCount=3, valueExpressions=[ParameterMarkerExpressionSegment(startIndex=59, stopIndex=59, parameterMarkerIndex=0), ParameterMarkerExpressionSegment(startIndex=62, stopIndex=62, parameterMarkerIndex=1), ParameterMarkerExpressionSegment(startIndex=65, stopIndex=65, parameterMarkerIndex=2), DerivedParameterMarkerExpressionSegment(super=ParameterMarkerExpressionSegment(startIndex=0, stopIndex=0, parameterMarkerIndex=3))], parameters=[c++, 180, 2])], generatedKeyContext=Optional[GeneratedKeyContext(columnName=cid, generated=true, generatedValues=[1012880134358700032])])
2024-06-27 00:24:02.518  INFO 24260 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: INSERT INTO course_1  ( cname,
user_id,
cstatus , cid)  VALUES  (?, ?, ?, ?) ::: [c++, 180, 2, 1012880134358700032]
2024-06-27 00:24:02.560  INFO 24260 --- [           main] ShardingSphere-SQL                       : Logic SQL: INSERT INTO course  ( cname,
user_id,
cstatus )  VALUES  ( ?,
?,
? )

其中包含雪花算法生成的id值

Actual SQL表示实际执行的sql语句

m1 ::: INSERT INTO course_1  ( cname,
user_id,
cstatus , cid)  VALUES  (?, ?, ?, ?) ::: [c++, 180, 2, 1012880134358700032]

Logic SQL:表示逻辑sql语句

INSERT INTO course  ( cname,
user_id,
cstatus )  VALUES  ( ?,
?,
? )

ShardingSphere就是将分片键经过分片策略,将逻辑sql转化成真实sql执行

Sharding-jdbc水平分库分表演示

需要将第二个库配置进yaml,并在第二个库中新建course_1和course_2表

spring:shardingsphere:datasource:#配置两个数据源m1,m2names: m1,m2#配置第一个数据源m1的详细信息m1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.94.124:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: 123456#配置第二个数据源m2的详细信息m2:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.188.99:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: 123456#配置分片表的详细信息sharding:tables:#配置逻辑表course的主键生成规则和详细的分片策略course:#配置逻辑表和物理表之间的关系,此时将m分成m1和m2将course分成course_1和course_2actual-data-nodes: m$->{1..2}.course_$->{1..2}# 配置主键生成规则key-generator:column: cidtype: SNOWFLAKEprops:worker:id: 1#配置库的策略database-strategy:inline:# 配置分片键sharding-column: cid#配置库的分片算法algorithm-expression: m$->{cid % 2 + 1}table-strategy:inline:# 配置分片键sharding-column: cid#配置分片算法algorithm-expression: course_$->{((cid+1)%4).intdiv(2)}props:sql:#开启sp  sql日志show: true

查询演示

查询所有的course表信息

public void findCourse(){QueryWrapper<Course> objectQueryWrapper = new QueryWrapper<>();List<Course> courses = courseMapper.selectList(objectQueryWrapper);System.out.println(courses.size());
}
2024-06-27 16:48:18.195  INFO 20524 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT  cid,cname,user_id,cstatus  FROM course
2024-06-27 16:48:18.195  INFO 20524 --- [           main] ShardingSphere-SQL                       : SQLStatement: SelectStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.SelectStatement@1d3c112a, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@2a140ce5), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@2a140ce5, projectionsContext=ProjectionsContext(startIndex=8, stopIndex=32, distinctRow=false, projections=[ColumnProjection(owner=null, name=cid, alias=Optional.empty), ColumnProjection(owner=null, name=cname, alias=Optional.empty), ColumnProjection(owner=null, name=user_id, alias=Optional.empty), ColumnProjection(owner=null, name=cstatus, alias=Optional.empty)]), groupByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.groupby.GroupByContext@1f71194d, orderByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.orderby.OrderByContext@db99785, paginationContext=org.apache.shardingsphere.sql.parser.binder.segment.select.pagination.PaginationContext@70716259, containsSubquery=false)
2024-06-27 16:48:18.195  INFO 20524 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  cid,cname,user_id,cstatus  FROM course_1
2024-06-27 16:48:18.196  INFO 20524 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2
2024-06-27 16:48:18.196  INFO 20524 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  cid,cname,user_id,cstatus  FROM course_1
2024-06-27 16:48:18.196  INFO 20524 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2

根据实际执行sql看出,其实是将m1,m2的course_1和course_2都去执行一遍SELECT cid,cname,user_id,cstatus FROM course_$,最后再聚合,将数据返回。

范围查询

根据cid的范围查询数据,如1L1806251962652463105L

public void findRangeCourse(){QueryWrapper<Course> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.between("cid", 1L, 1806251962652463105L);List<Course> courses = courseMapper.selectList(objectQueryWrapper);System.out.println(courses.size());}

此时由于是inline的关系,会抛异常

Cause: java.lang.IllegalStateException: Inline strategy cannot support this type sharding:RangeRouteValue(columnName=cid, tableName=course, valueRange=[1‥1806251962652463105])

分片策略是inline无法支持范围查询。

标准策略的定制

Sharding-jdbc支持分库分表的标准策略模式,可以根据自己需求定制策略。

分为精准策略range策略.

  • 精准策略需要实现PreciseShardingAlgorithm
  • range策略需要实现RangeShardingAlgorithm

下面分别定义库和表的策略,其中库的策略为

public class CourseDataSourcePrecisAlgorithm implements PreciseShardingAlgorithm<Long> {private static final AtomicInteger COUNTER = new AtomicInteger(0);/*** 从availableTargetNames中根据分片键preciseShardingValue的值,选择一个数据节点名称。** @param availableTargetNames 参数包含了所有可用的数据节点名称,比如数据源或数据表的名称。* @param preciseShardingValue 参数包含了分片键的值和逻辑表名称。* @return*/@Overridepublic String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> preciseShardingValue) {// 获取分片键的值//选取数据源m1,m2int andIncrement = COUNTER.getAndIncrement();if(andIncrement % 2 == 0){return "m1";}else{return "m2";}}
}

range并没有策略,此时返回所有的库,则ShardingSphere在执行范围查询的时候,会遍历所有的库。

public class CourseDataSourceRangeAlgorithm implements RangeShardingAlgorithm<Long> {@Overridepublic Collection<String> doSharding(Collection<String>  availableTargetNames, RangeShardingValue<Long> rangeShardingValue){return availableTargetNames;}
}

表的策略为

public class CourseDataSourcePrecisAlgorithm implements PreciseShardingAlgorithm<Long> {/*** 从availableTargetNames中根据分片键preciseShardingValue的值,选择一个数据节点名称。* 选取数据源m1,m2* 因为有4张表,所以利用cid对4取模,得到一个余数,余数是如果是0和1,则选择m1,如果是2和3,则选择m2* @param availableTargetNames 参数包含了所有可用的数据节点名称,比如数据源或数据表的名称。* @param preciseShardingValue 参数包含了分片键的值和逻辑表名称。* @return*/@Overridepublic String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> preciseShardingValue) {// 获取分片键的值Long cid = preciseShardingValue.getValue();long mod = cid % 4;if(mod == 0 || mod == 1){return "m1";}else if(mod == 2 || mod == 3){return "m2";}else{throw new UnsupportedOperationException();}}
}
public class CourseTablePrecisAlgorithm implements PreciseShardingAlgorithm<Long> {/*** 因为有4张表,所以利用cid对4取模,得到一个余数,* 余数如果是0和1,则选择m1,如果是0,则选择m1->course_1,如果是1,则选择m1->course_2* 余数如果是2和3,则选择m2,,如果是2,则选择m2->course_1,如果是3,则选择m2->course_2* 这里由于雪花算法在低并发下,由于同一毫秒只分配一个id则最后12位都是0,所以不存在2^0,故而雪花生成的id是2,4的倍数,取模偏移0区* 数据量少时或者tps低时尽量避免取模2,4,如分片键* @param collection* @param preciseShardingValue* @return*/@Overridepublic String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {//怎么根据cid来判断路由到哪个表,cid这里既需要经过算法成为1,也要成为2,还不能跟dataSource路由冲突long mod = preciseShardingValue.getValue() % 4;//根据mod能知道该条数据应该路由到哪个库中if(mod == 0 || mod == 2){String key = preciseShardingValue.getLogicTableName() + "_" + 1;if(collection.contains(key)){return key;}throw new UnsupportedOperationException();}else if(mod == 1 || mod == 3){String key = preciseShardingValue.getLogicTableName() + "_" + 2;if(collection.contains(key)) {return key;}throw new UnsupportedOperationException();}throw new UnsupportedOperationException();}
}

yaml中需要更改为如下配置

spring:shardingsphere:datasource:#配置第一个数据源m1names: m1,m2#配置第一个数据源m1的详细信息m1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.94.124:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: SXD6VRjqm2:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.188.99:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: xDLnuQtK#配置分片表的详细信息sharding:tables:#配置逻辑表course的主键生成规则和详细的分片策略course:#配置逻辑表和物理表之间的关系,此时将course分成course_1和course_2actual-data-nodes: m$->{1..2}.course_$->{1..2}# 配置主键生成规则key-generator:column: cidtype: SNOWFLAKEprops:worker:id: 1#配置库的策略database-strategy:standard:# 配置分片策略precise-algorithm-class-name: cn.axj.sharding.ShardingAlgorithmConfig.CourseDataSourcePrecisAlgorithmrange-algorithm-class-name: cn.axj.sharding.ShardingAlgorithmConfig.CourseDataSourceRangeAlgorithm# 配置分片键sharding-column: cidtable-strategy:standard:range-algorithm-class-name: cn.axj.sharding.ShardingAlgorithmConfig.CourseTableRangeAlgorithmprecise-algorithm-class-name: cn.axj.sharding.ShardingAlgorithmConfig.CourseTablePrecisAlgorithm# 配置分片键sharding-column: cidprops:sql:#开启sp  sql日志show: true

执行范围查询

public void findRangeCourse(){QueryWrapper<Course> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.between("cid", 1L, 1806251962652463105L);List<Course> courses = courseMapper.selectList(objectQueryWrapper);System.out.println(courses.size());
}
2024-06-27 17:27:00.263  INFO 11432 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  cid,cname,user_id,cstatus  FROM course_1 WHERE (cid BETWEEN ? AND ?) ::: [1, 1806251962652463105]
2024-06-27 17:27:00.263  INFO 11432 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2 WHERE (cid BETWEEN ? AND ?) ::: [1, 1806251962652463105]
2024-06-27 17:27:00.263  INFO 11432 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  cid,cname,user_id,cstatus  FROM course_1 WHERE (cid BETWEEN ? AND ?) ::: [1, 1806251962652463105]
2024-06-27 17:27:00.263  INFO 11432 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  cid,cname,user_id,cstatus  FROM course_2 

可以看到实际执行sql如上。每个库每个表都查询,最后聚合。

标准策略针对in、=、between三种范围查询

复合策略的定制

多个字段组合的查询,则需要用到复合策略complex

spring:shardingsphere:datasource:#配置第一个数据源m1names: m1,m2#配置第一个数据源m1的详细信息m1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.94.124:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: SXD6VRjqm2:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.188.99:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: xDLnuQtK#配置分片表的详细信息sharding:tables:#配置逻辑表course的主键生成规则和详细的分片策略course:#配置逻辑表和物理表之间的关系,此时将course分成course_1和course_2actual-data-nodes: m$->{1..2}.course_$->{1..2}# 配置主键生成规则key-generator:column: cidtype: SNOWFLAKEprops:worker:id: 1#配置库的策略database-strategy:complex:#配置分片键sharding-columns: cid,user_id# 配置分片策略algorithm-class-name: cn.axj.sharding.ShardingAlgorithmConfig.CourseDatabaseComplexAlgorithmtable-strategy:complex:sharding-columns: cid,user_idalgorithm-class-name: cn.axj.sharding.ShardingAlgorithmConfig.CourseTableComplexAlgorithmprops:sql:#开启sp  sql日志show: true
public class CourseDatabaseComplexAlgorithm implements ComplexKeysShardingAlgorithm<Long> {@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> complexKeysShardingValue) {Long userId = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("cid").iterator().next();Long cid = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("cid").iterator().next();// 自定义分片逻辑,示例中简单处理// 假设根据 user_id 和 order_id 进行取模分片String dataSourceName = "m" + ((userId + cid) % availableTargetNames.size() + 1);for (String targetName : availableTargetNames) {if (targetName.endsWith(dataSourceName)) {return Collections.singleton(targetName); // 返回匹配的表名}}throw new IllegalArgumentException("No precise sharding available for " + complexKeysShardingValue);}
}
public class CourseTableComplexAlgorithm implements ComplexKeysShardingAlgorithm<Long> {@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> complexKeysShardingValue) {Long userId = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("cid").iterator().next();Long cid = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("cid").iterator().next();// 自定义分片逻辑,示例中简单处理// 假设根据 user_id 和 order_id 进行取模分片String tableName = complexKeysShardingValue.getLogicTableName() + "_" + ((userId + cid) % availableTargetNames.size() + 1);for (String targetName : availableTargetNames) {if (targetName.endsWith(tableName)) {return Collections.singleton(targetName); // 返回匹配的表名}}throw new IllegalArgumentException("No precise sharding available for " + complexKeysShardingValue);}
}

hint策略的定制

hint策略,按照与sql无关的值进行分片,所以无需分片键这些,只需要一个分片算法

分片的值通过HintManger手动设置, 如下示例。

AtomicInteger atomicInteger = new AtomicInteger(0);
HintManager instance = HintManager.getInstance();
instance.setDatabaseShardingValue(atomicInteger.getAndIncrement() % 2 + 1);
instance.addTableShardingValue("course", atomicInteger.getAndIncrement() % 2 + 1);
public class CourseDatabaseHintAlgorithm  implements HintShardingAlgorithm<String> {@Overridepublic Collection<String> doSharding(Collection<String> collection, HintShardingValue<String> hintShardingValue) {String key = "m" + hintShardingValue.getValues().toArray()[0];if(collection.contains(key)){return Collections.singletonList(key);}throw new UnsupportedOperationException();}
}
public class CourseTableHintAlgorithm implements HintShardingAlgorithm<Long> {@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Long> shardingValue){String logicTableName = shardingValue.getLogicTableName();//该值需要在查询或者DDL的时候通过HintManager设置Collection<Long> values = shardingValue.getValues();String key = logicTableName + "_" + shardingValue.getValues().toArray()[0];if(availableTargetNames.contains(key)){return Collections.singletonList(key);}throw new UnsupportedOperationException();}
}
spring:shardingsphere:datasource:#配置第一个数据源m1names: m1,m2#配置第一个数据源m1的详细信息m1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.94.124:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: SXD6VRjqm2:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://47.109.188.99:3306/coursedb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: xDLnuQtK#配置分片表的详细信息sharding:tables:#配置逻辑表course的主键生成规则和详细的分片策略course:#配置逻辑表和物理表之间的关系,此时将course分成course_1和course_2actual-data-nodes: m$->{1..2}.course_$->{1..2}# 配置主键生成规则key-generator:column: cidtype: SNOWFLAKEprops:worker:id: 1#配置库的策略database-strategy:hint:algorithm-class-name:  cn.axj.sharding.ShardingAlgorithmConfig.CourseDatabaseHintAlgorithmtable-strategy:hint:algorithm-class-name: cn.axj.sharding.ShardingAlgorithmConfig.CourseTableHintAlgorithmprops:sql:#开启sp  sql日志show: true

比如在新增数据的时候,需要利用HintManage将分片值传进去

public void addHintCourse(){AtomicInteger atomicInteger = new AtomicInteger(0);HintManager instance = HintManager.getInstance();for (int i = 0; i < 200; i++) {instance.setDatabaseShardingValue(atomicInteger.getAndIncrement() % 2 + 1);instance.addTableShardingValue("course", atomicInteger.getAndIncrement() % 2 + 1);Course course = new Course();course.setCname("c++");course.setUserid(180L);course.setCstatus("2");courseMapper.insert(course);}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com