跟我学ShardingSphere之数据分片策略

在前面一篇《跟我学ShardingSphere之SpringBoot + ShardingJDBC分库》我们介绍了如何利用ShardingJDBC进行分库,用到了inline行表达式分片策略,ShardingSphere还有其他几种分片策略,下面我们来介绍一下

分片键

用于分片的字段,是将数据库或表拆分的字段,比如,我可以使用user_id作为分片键将用户数据分到不同的表中,这里的user_id就是分片键,除了这种单字段分片,ShardingSphere还支持多个分片字段。SQL中如果没有分片字段,将执行全路由,也就是会把SQL发送到所有的数据分片上执行,性能较差。

分片算法

分片算法描述的是如何进行分片,需要结合分片键使用,比如我需要使用user_id对2取模进行分表,那么这里取模就是分片算法,ShardingShpere支持>、<、=、IN和Between分片。这些分片算法需要根据实际的业务开发,ShardingSphere没有默认的分片算法,所以你得根据自己的业务来开发自己的分片算法,不过也挺简单的,ShardingSphere已经预留好了对应的接口,你实现对应的接口就好了

目前ShardingSphere将常用的分片算法进行抽象,定义了四种分片算法

1、精确分片算法

对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。

2、范围分片算法

对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合StandardShardingStrategy使用。

3、复合分片算法

对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。

4、Hint分片算法

对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用

分片策略

包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供5种分片策略

1、标准分片策略

对应StandardShardingStrategy。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。

2、复合分片策略

对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。

3、行表达式分片策略

对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。

4、Hint分片策略

对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略

5、不分片策略

对应NoneShardingStrategy。不分片的策略。

分片示例

我们还是通过一个分表的示例来演示一下,如何根据自己的需求来开发自己的分片算法

需求:业务上存在多个分支机构,需要将不同分支的客户拆分到不同的表

分析:通过需求可知,这是个单分片的需求,我们选择标准分片就可以满足需求

1、先建表

CREATE TABLE `tb_cust` (
  `cust_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `cust_name` varchar(20) NOT NULL COMMENT '用户名称',
  `branch_id` char(3) NOT NULL COMMENT '分公司',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8 COMMENT='客户信息表';

按不同的分支机构建不同的表

在这里插入图片描述

从表名可以看出来,我们有fc5、fdg、fdm、fdw这几个分支机构

2、分片算法

标准分片策略需要实现PreciseShardingAlgorithm接口

/**
 * 精确分片算法(可用于分库、分表)
 * 公众号【Java天堂】
 */
public class BranchPreciseShardingAlgorithm implements PreciseShardingAlgorithm<String> {
    @Override
    public String doSharding(Collection<String> shardingNameList, PreciseShardingValue<String> preciseShardingValue) {
        String key = preciseShardingValue.getValue();
        //遍历所有的数据分片,与分片键(key)比较,匹配就返回当前数据分片
        for(String shardingName : shardingNameList){
            if(shardingName.endsWith(key.toLowerCase())){
                return shardingName;
            }
        }
        throw new IllegalArgumentException();
    }
}

3、分片策略配置

server:
  port: 8090

spring:
  main:
    allow-bean-definition-overriding: true

  shardingsphere:
    datasource:
      names: testdb0,testdb1
      testdb0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/testdb0?useUnicode=true&characterEncoding=utf-8
        username: root
        password: 123456
      testdb1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/testdb1?useUnicode=true&characterEncoding=utf-8
        username: root
        password: 123456

    # 分库、分表配置
    sharding:
      tables:
        tb_cust:
          actual-data-nodes: testdb0.tb_cust_$->{['fdg','fc5','fdw','fdm']}
          # 分表配置
          table-strategy:
            standard:
              sharding-column: branch_id
              precise-algorithm-class-name: com.kxg.shardingRule.BranchPreciseShardingAlgorithm

    props:
      sql.show: true

从上面的配置可以看出来,我们分表的策略不再是inline,而是换成standard,表示标准分片策略

分片策略也换成了我们自己写的分片算法:BranchPreciseShardingAlgorithm

@Data
@TableName("tb_cust")
public class Cust {
    private Long custId;
    private String custName;
    private String branchId;
}
public interface CustMapper extends BaseMapper<Cust> {

}
@Service
public class CustService {
    @Autowired
    private CustMapper custMapper;

    public void insert(Cust cust){
        int count = custMapper.insert(cust);
        System.out.println("insert count:" + count);
    }

    public Cust getCust(Long custId){
        return custMapper.selectById(custId);
    }
}
@RestController
public class CustController {
    @Autowired
    private CustService custService;

    @RequestMapping("/cust/add")
    public String addUser(@RequestBody Cust cust){
        custService.insert(cust);
        return "ok";
    }

    @RequestMapping("/cust/get")
    @ResponseBody
    public Cust getUser(Long custId){
        return custService.getCust(custId);
    }
}

启动程序,可以看到如下打印:

tables:
  tb_cust:
    actualDataNodes: testdb0.tb_cust_$->{['fdg','fc5','fdw','fdm']}
    logicTable: tb_cust
    tableStrategy:
      standard:
        preciseAlgorithmClassName: com.kxg.shardingRule.BranchPreciseShardingAlgorithm
        shardingColumn: branch_id

表示已经加载配置成功

我们试着添加两个Cust信息,如下
在这里插入图片描述
在这里插入图片描述
我们可以看到控制台打印的SQL语句:

Logic SQL: INSERT INTO tb_cust  ( cust_id,cust_name,branch_id )  VALUES  ( ?,?,? )
Actual SQL: testdb0 ::: INSERT INTO tb_cust_fdg  ( cust_id,cust_name,branch_id )  VALUES  (?, ?, ?) ::: [1, 客户-FDG, FDG]

Logic SQL: INSERT INTO tb_cust  ( cust_id,cust_name,branch_id )  VALUES  ( ?,?,? )
Actual SQL: testdb0 ::: INSERT INTO tb_cust_fc5  ( cust_id,cust_name,branch_id )  VALUES  (?, ?, ?) ::: [2, 客户-FC5, FC5]

从执行的SQL可以看到,是根据我们的预期进行分表操作的,下面去数据库对应的表查看一下对应的数据是不是正确插入
在这里插入图片描述

可以看到,两次的数据根据不同的branchId字段插入到不同的表中,达到了根据branchId分表的目的

如果感觉对你有些帮忙,请收藏好,你的关注和点赞是对我最大的鼓励!
如果想跟我一起学习,坚信技术改变世界,请关注【Java天堂】公众号,我会定期分享自己的学习成果,第一时间推送给您

在这里插入图片描述

posted @ 2021-09-02 21:57  果子爸聊技术  阅读(36)  评论(0编辑  收藏  举报