一、在上一节中提到了分库分表的策略。分库策略算法GroupIDAndCollectTimeDBShardingAlgorithm和分表策略算法CollectTimeYYYYMMDDTBShardingAlgorithm
分片策略算法有很多,但是一般的都是需要自定义,dangdangwang提供了最顶层的实现,但是具体的算法需要我们自己来写。
这里有两个自定义的算法,单分片算法和多分片算法,单分片算法是多分片算法的一种简单形式,所以完全可以用多分片算法代替单分片算法,下面两种形式是等价的。
newTableShardingStrategy("order_id",newSingleKeyShardingAlgorithm()))newTableShardingStrategy(Arrays.asList("order_id"),newMultiKeyShardingAlgorithm()))
同时在算法内部,dosharding等方法的shardingvalue入参根据使用算法类型不同而不同,单分片算法方public String doEqualSharding(final Collection<String> dataSourceNames,final ShardingValue<Integer> shardingValue)
多分片算法public Collection<String>doSharding(final Collection<String> availableTargetNames,final Collection<ShardingValue<?>> shardingValues)
根据数据源策略和表策略,单分片与多分片,这两种组合一共产生了4中可供实现的分片算法的接
- 单分片键数据源分片算法
SingleKeyDatabaseShardingAlgorithm
- 单分片表分片算法
SingleKeyTableShardingAlgorithm
- 多分片键数据源分片算法
MultipleKeyDatabaseShardingAlgorithm
- 多分片表分片算法
MultipleKeyTableShardingAlgorithm
单分片建算法需要实现三个方法,下面以单分片建数据源分片算法举例:
@Override public String doEqualSharding(final Collection<String> availableTargetNames,final ShardingValue<Integer> shardingValue) @Override public Collection<String>doInSharding(final Collection<String> availableTargetNames,final ShardingValue<Integer> shardingValue) @Override public Collection<String>doBetweenSharding(final Collection<String> availableTargetNames,final ShardingValue<Integer> shardingValue)
这三种算法作用如下 - doEqualSharding
在WHERE使用=
作为条件分片键。算法中使用shardingValue.getValue()
获取等=
后的值 -doInSharding
在WHERE使用IN
作为条件分片键。算法中使用shardingValue.getValues()
获取IN
后的值 - doBetweenSharding
在WHERE使用BETWEEN
作为条件分片键。算法中使用shardingValue.getValueRange()
获取BETWEEN
后的值
多分片建算法适用于比较复杂的场景,为了提高灵活性故只提供了一个方法实现
public Collection<String>doSharding(final Collection<String> availableTargetNames,final Collection<ShardingValue<?>> shardingValues)
算法实现的时候根据shardingValue.getType来获取条件是= .IN还是between
举个例:
db0 ├── t_order_00 user_id以a偶数 order_id为偶数 ├── t_order_01 user_id以a偶数 order_id为奇数 ├── t_order_10 user_id以b奇数 order_id为偶数 └── t_order_11 user_id以b奇数 order_id为奇数
public final class MultipleKeysModuloTableShardingAlgorithm implements MultipleKeysTableShardingAlgorithm { @Override public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue<?>> shardingValues) { Set<Integer> orderIdValueSet = getShardingValue(shardingValues, "order_id"); Set<Integer> userIdValueSet = getShardingValue(shardingValues, "user_id"); List<String> result = new ArrayList<>(); /* userIdValueSet[10,11] + orderIdValueSet[101,102] => valueResult[[10,101],[10,102],[11,101],[11,102]] */ Set<List<Integer>> valueResult = Sets.cartesianProduct(userIdValueSet, orderIdValueSet); for (List<Integer> value : valueResult) { String suffix = Joiner.on("").join(value.get(0) % 2, value.get(1) % 2); for (String tableName : availableTargetNames) { if (tableName.endsWith(suffix)) { result.add(tableName); } } } return result; } private Set<Integer> getShardingValue(final Collection<ShardingValue<?>> shardingValues, final String shardingKey) { Set<Integer> valueSet = new HashSet<>(); ShardingValue<Integer> shardingValue = null; for (ShardingValue<?> each : shardingValues) { if (each.getColumnName().equals(shardingKey)) { shardingValue = (ShardingValue<Integer>) each; break; } } if (null == shardingValue) { return valueSet; } switch (shardingValue.getType()) { case SINGLE: valueSet.add(shardingValue.getValue()); break; case LIST: valueSet.addAll(shardingValue.getValues()); break; case RANGE: for (Integer i = shardingValue.getValueRange().lowerEndpoint(); i <= shardingValue.getValueRange().upperEndpoint(); i++) { valueSet.add(i); } break; default: throw new UnsupportedOperationException(); } return valueSet; } }