shardingjdbc简单使用之五种分片策略


上源码:

@Getter
@Setter
public class YamlShardingStrategyConfiguration implements YamlConfiguration {
    
    private YamlStandardShardingStrategyConfiguration standard;
    
    private YamlComplexShardingStrategyConfiguration complex;
    
    private YamlHintShardingStrategyConfiguration hint;
    
    private YamlInlineShardingStrategyConfiguration inline;
    
    private YamlNoneShardingStrategyConfiguration none;
}

即在yml配置文件中对应分库分表策略:
在这里插入图片描述
每一种不同的分片策略各自的属性值不同

1、inline(行表达式)

使用很简单,通过书写表达式即可完成(groovy表达式)

@Getter
@Setter
public final class YamlInlineShardingStrategyConfiguration implements YamlBaseShardingStrategyConfiguration {
    
    private String shardingColumn;
    
    private String algorithmExpression;
}

与配置文件对应
在这里插入图片描述

2、standard

这里用分表来举例
指定分片键,自定义分片策略算法

@Getter
@Setter
public final class YamlStandardShardingStrategyConfiguration implements YamlBaseShardingStrategyConfiguration {
    
    private String shardingColumn;
    
    private String preciseAlgorithmClassName;
    
    private String rangeAlgorithmClassName;
}

preciseAlgorithmClassName:精准算法(sql语句中有=、in) 此必须实现
rangeAlgorithmClassName:范围算法(between and)
preciseAlgorithmClassName使用场景:以分片键作为查询字段并使用=、in

public interface PreciseShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {
    
    /**
     * Sharding.
     * 
     * @param availableTargetNames available data sources or tables's names
     * @param shardingValue sharding value
     * @return sharding result for data source or table's name
     */
    String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<T> shardingValue);
}

首先准备配置

	sharding:
      tables:
        #逻辑表名
        user:
          actual-data-nodes: db1.table_$->{[1,2]}
          #actual-data-nodes: db.table_1,db.table_2
          key-generator:
            column: id #自定填充字段
            type: SNOWFLAKE #雪花算法  UUID、SNOWFLAKE两种(实现ShardingKeyGenerator接口)
          table-strategy: #分表策略
            standard:
              shardingColumn: id
              preciseAlgorithmClassName: com.example.sharding_jdbc.standard.MyPreciseShardingAlgorithm
              #rangeAlgorithmClassName:

自定义的PreciseShardingAlgorithm:
在这里插入图片描述
打上断点:测试插入一条数据运行

		User user = new User();
        user.setName("sam");
        user.setAge(22);
        user.setSex(1);
        userMapper.insert(user);

在这里插入图片描述
doSharding方法的参数
1、availableTargetNames:所有的数据存储节点
2、shardingValue:分片键值
这里所有存储节点与配置文件中的对应,配置的分片键就是id,这里也拿到。
doSharding方法的参数
方法的返回值就是最终选择的表
实现一个偶数存table_1、奇数id存table_2

public class MyPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        for (String targetName : availableTargetNames) {
            //偶数存table_1、基数存table_2
            String value = shardingValue.getValue() % availableTargetNames.size() +1+ "";
            if(targetName.endsWith(value)){
                return targetName;
            }
        }
        throw new RuntimeException("分片策略出错");
    }
}

运行测试结果:

Actual SQL: db1 ::: INSERT INTO table_2   (id, age, name, sex) VALUES (?, ?, ?, ?) ::: [1475333493534035969, 22, sam, 1]

rangeAlgorithmClassName
测试范围查询:使用场景sql语句中使用分片键做查询并使用between and做范围查询

 List<User> users = userMapper.selectList(new QueryWrapper<User>().gt("age", 20));

如果不实现RangeShardingAlgorithm,默认会从所以的数据节点中查询然后合并结果

: Actual SQL: db1 ::: SELECT  id,age,name,sex  FROM table_1 
 WHERE (age > ?) ::: [20]
  Actual SQL: db1 ::: SELECT  id,age,name,sex  FROM table_2 
 WHERE (age > ?) ::: [20]

自定义实现RangeShardingAlgorithm

public class MyRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        Set<String> list = new HashSet<>();
        Long lower = shardingValue.getValueRange().lowerEndpoint();
        Long upper = shardingValue.getValueRange().upperEndpoint();
        list.add("table_1");
        return list;
    }
}

方法参数

1、availableTargetNames所有实际数据节点
2、shardingValue范围值
方法返回值
返回查询的最终数据节点集合
这里我指定返回单一数据的集合(可自定义逻辑返回集合),那么最终查询只会在这一个数据节点上查询
查询语句:要以对应分片键作为查询字段

List<User> users = userMapper.selectList(new QueryWrapper<User>()
                .between("id", 1475333493534035969L,1475333493534035979L));

日志

Actual SQL: db1 ::: SELECT  id,age,name,sex  FROM table_1 
 
 WHERE (id BETWEEN ? AND ?) ::: [1475333493534035969, 1475333493534035979]

最终只在指定的数据节点上做查询

3、hint

不需要在配置文件中指定分片键,在代码中定义最终选择的库和表

@Getter
@Setter
public final class YamlHintShardingStrategyConfiguration implements YamlBaseShardingStrategyConfiguration {
    
    private String algorithmClassName;
}

配置文件:分库分表使用同一个实现HintShardingAlgorithm的类

	  tables:
        #逻辑表名
        user:
          actual-data-nodes: db1.table_$->{[1,2]}
          database-strategy:
            hint:
              algorithm-class-name: com.example.sharding_jdbc.hint.MyHintShardingAlgorithm
          table-strategy: #分表策略
            hint:
              algorithmClassName: com.example.sharding_jdbc.hint.MyHintShardingAlgorithm

实现HintShardingAlgorithm接口

public class MyHintShardingAlgorithm implements HintShardingAlgorithm<Integer> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Integer> shardingValue) {
		ArrayList<String> list = new ArrayList<String>() ;
        for (String targetName : availableTargetNames) {
            if(shardingValue.getValues().contains(targetName)){
                list.add(targetName);//选择库、表
                break;
            }
        }
        return list;
    }
}

在调用sql语句之前要使用hintmannager设置分库分表的分片键,因为hintmannager是由ThreadLocal管理,每次使用记得调用clear()从threadLocal中清除

public static HintManager getInstance() {
        Preconditions.checkState(null == HINT_MANAGER_HOLDER.get(), "Hint has previous value, please clear first.");
        HintManager result = new HintManager();
        HINT_MANAGER_HOLDER.set(result);
        return result;
    }

测试

		HintManager.clear();
        HintManager hintManager = HintManager.getInstance();
        hintManager.addTableShardingValue("user","table_2");
        hintManager.addDatabaseShardingValue("user","db1");
       // hintManager.setDatabaseShardingValue("db1");
        List<User> users = userMapper.selectList(new QueryWrapper<User>().select("*"));

addTableShardingValue("user","table_2"):参数一是要指定分表的逻辑表名(配置文件中配置的),参数二设置最终选择的实际数据表
addDatabaseShardingValue("user","db1"):参数一是要指定分表的逻辑表名(配置文件中配置的),参数二设置最终选择的实际数据库
setDatabaseShardingValue:之分库不分表
待定…

4、complex

可以配置多个分片键
在这里插入图片描述

@Getter
@Setter
public final class YamlComplexShardingStrategyConfiguration implements YamlBaseShardingStrategyConfiguration {
    
    private String shardingColumns;
    
    private String algorithmClassName;
}

自定义策略实现ComplexKeysShardingAlgorithm接口

public interface ComplexKeysShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {
    
    /**
     * Sharding.
     * 
     * @param availableTargetNames 实际存储数据节点
     * @param shardingValue 分片键值
     * @return 最终要操作的数据节点
     */
    Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<T> shardingValue);
}

测试查询语句,这里只使用到配置的分片键中的id

List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("id", 1L));

在这里插入图片描述
shardingValue参数只会包含sql语句中使用到的id

测试使用两个分片键

List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("id", 1L)
                .eq("sex",0));

在这里插入图片描述
最后按照自己的逻辑返回最终要查询的数据节点集合

5、none

即不使用分片策略
在这里插入图片描述
注意配置,因为

public final class YamlNoneShardingStrategyConfiguration implements YamlBaseShardingStrategyConfiguration {
}

none对应的类没有任何属性,需要自定义再加一层才能解析成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值