初探Sharding-JDBC订单表分片实现

时间:2024-11-15 15:53:49

设计订单系统有两个数据库db_order_01和db_order_02。每个数据库分别有t_order_0和t_order_1两张订单表。

订单表设计有订单ID(order_id),用户ID(user_id),商户ID(merchant_id)。假设商户查看订单操作要比用户查看订单的操作更加频繁。避免商户查询订单时跨库查询,用商户ID对数据库数量取模的方式将同一个商户的订单路由到同一个数据库中。通过对用户ID进行Hash后取模,将同一个用户的订单路由到同一张表中。以上设计主要是为了使用取模算法和哈希取模算法????。

订单数据库和表创建DDL: t_order.sql

一、ShardingSphereDataSource数据源配置

使用的Spring boot、ShardingSphere-JDBC和MyBatis的依赖如下:

  1. <dependencyManagement>
  2. <dependencies>
  3. <dependency>
  4. <groupId></groupId>
  5. <artifactId>spring-boot-dependencies</artifactId>
  6. <version>2.6.8</version>
  7. <type>pom</type>
  8. <scope>import</scope>
  9. </dependency>
  10. <dependency>
  11. <groupId></groupId>
  12. <artifactId>shardingsphere-jdbc-core</artifactId>
  13. <version>5.2.0</version>
  14. </dependency>
  15. <dependency>
  16. <groupId></groupId>
  17. <artifactId>mybatis-spring-boot-starter</artifactId>
  18. <version>2.2.2</version>
  19. </dependency>
  20. </dependencies>
  21. </dependencyManagement>

(1)创建db_order_01和db_order_02数据源

  1. /**
  2. * HikariConfig
  3. * @param database db
  4. * @return dataSource config
  5. */
  6. private HikariConfig create(String database) {
  7. (database, "database require not null");
  8. HikariConfig config = new HikariConfig();
  9. (USERNAME);
  10. (PASSWORD);
  11. (DRIVER_NAME);
  12. (("jdbc:mysql://localhost:3306/%s", database));
  13. return config;
  14. }
  15. /**
  16. * create DataSource
  17. * @param database db
  18. * @return dataSource
  19. */
  20. private DataSource createDataSource(String database) {
  21. return new HikariDataSource(this.create(database));
  22. }
  23. @Bean
  24. public DataSource dbOrder01DataSource() {
  25. return this.createDataSource("db_order_01");
  26. }
  27. @Bean
  28. public DataSource dbOrder02DataSource() {
  29. return new HikariDataSource(this.create("db_order_02"));
  30. }

(2)初始化数据源集合

  1. /**
  2. * 初始化数据源
  3. * @return dataSource map
  4. */
  5. private Map<String, DataSource> initDataSourceMap() {
  6. Map<String, DataSource> dataSourceMap = new HashMap<>();
  7. // order databases
  8. ("db_order_0", this.dbOrder01DataSource());
  9. ("db_order_1", this.dbOrder02DataSource());
  10. return dataSourceMap;
  11. }

请注意数据源集合中database的key,该key在后面的表分片规则时指定实际数据节点时需要使用。

(3)配置分片规则并创建ShardingSphereDataSource

  1. @Bean
  2. @Primary
  3. public DataSource shardingDateSource() {
  4. // 分片规则集
  5. List<RuleConfiguration> dbRules = new ArrayList<>();
  6. ShardingRuleConfiguration shardingRule = new ShardingRuleConfiguration();
  7. // 设置默认的分片键,同一个商户的订单放到一个数据库中
  8. String defaultShardingColumn = "merchant_id";
  9. (defaultShardingColumn);
  10. // 创建默认database分片策略
  11. (this.createStandardShardingStrategy(
  12. defaultShardingColumn, "MOD"));
  13. // 创建默认的表分片策略,同一个用户的订单放到一张表中
  14. String userIdShardingColumn = "user_id";
  15. (this.createStandardShardingStrategy(
  16. userIdShardingColumn, "HASH_MOD"));
  17. // 分片算法properties属性配置
  18. Map<String, AlgorithmConfiguration> shardingAlgorithmsConf = ();
  19. // 设置分片算法属性配置
  20. (this.shardingAlgoConfig());
  21. // key gen算法属性配置
  22. Map<String, AlgorithmConfiguration> keyGenerators = ();
  23. (this.keyGenAlgoConfig());
  24. // order table sharding 配置
  25. ShardingTableRuleConfiguration orderTableRule = new ShardingTableRuleConfiguration(
  26. "t_order", "db_order_$->{0..1}.t_order_$->{0..1}");
  27. // order_id gen
  28. KeyGenerateStrategyConfiguration orderIdGen =
  29. new KeyGenerateStrategyConfiguration("order_id", "SNOWFLAKE");
  30. (orderIdGen);
  31. List<ShardingTableRuleConfiguration> tableRuleConfigs = new ArrayList<>();
  32. // add t_order rule
  33. (orderTableRule);
  34. // config t_user table sharding rule
  35. ShardingTableRuleConfiguration tUserTableShardingRule = this.configUserTableShardingRule();
  36. // add t_user rule
  37. (tUserTableShardingRule);
  38. // set tables rule
  39. ().addAll(tableRuleConfigs);
  40. (shardingRule);
  41. DataSource primaryDataSource = null;
  42. try {
  43. ModeConfiguration modeConfiguration = this.createModeConfiguration();
  44. primaryDataSource = (modeConfiguration,
  45. this.initDataSourceMap(), dbRules, this.shadingDataSourceProps());
  46. } catch (SQLException e) {
  47. ("create primaryDataSource error:", e);
  48. }
  49. return (primaryDataSource, "primaryDataSource require not null");
  50. }

配置表分片规则(ShardingTableRuleConfiguration)时,存在多个数据源和多个表分片时,可以使用Groovy表达式。简单配置示例如下:

 

注意actualDataNodes的配置,如果配置不正确,在执行SQL时会出现找不到路由数据源的异常。 

 二、执行测试并验证

其中MyBatis的配置这里就不就行介绍了。源码地址: /qinshizhang/shard-jdbc

下载后简单配置一个数据库信息即可启动并运行。

(1)测试新增订单数据 

  1. @Test
  2. void insertSelective() {
  3. this.checkMapper();
  4. OrderEntity order = new OrderEntity();
  5. (());
  6. ((47));
  7. ((Long) ());
  8. int insertRows = (order);
  9. assertEquals(1, insertRows);
  10. }

测试执行结果如下: 

 其中商户ID=6,对2取模结果为0,数据路由到db_order_0数据库中。用户ID是468323156650622977,该值hash对2取模结果为1,数据路由到t_order_1表中。

到此,第一个使用ShardingSphere-JDBC进行订单数据进行分库分表的示例完成了,后续逐渐加入用户、产品、库存等表的操作。????????????一起加入学习吧!!????????????