sharding-jdbc的作用就不必做過多的解釋了,主要用途是分庫分表;首先先了解下分庫分表的策略吧。
1 分片鍵
分片鍵即在分庫分表時根據表中的某一個或者多個字段爲依據,以一定的邏輯進行分割,例如根據自增的主鍵求模的規則進行分片等。
2 分片算法
分片算法結合分片鍵對具體的數據進行分片;支持通過=、BETWEEN和IN分片。分片算法需要應用方開發者自行實現,可實現的靈活度非常高。分片算法有四種:
(1)精確分片算法
對應PreciseShardingAlgorithm,用於處理使用單一鍵作爲分片鍵的=與IN進行分片的場景。需要配合standardShardingStrategy使用。
(2)範圍分片算法
對應RangeShardingAlgorithm,用於處理使用單一鍵作爲分片鍵的BETWEEN AND進行分片的場景。需要配合StandardShardingStrategy使用。
(3)複合分片算法
對應ComplexKeysShardingAlgorithm,用於處理使用多鍵作爲分片鍵進行分片的場景,包含多個分片鍵的邏輯較複雜,需要應用開發者自行處理其中的複雜度。需要配合ComplexShardingStrategy使用。
(4) Hint分片算法
對應HintShardingAlgorithm,用於處理使用Hint行分片的場景。需要配合HintShardingStrategy使用。
3 分片策略
包含分片鍵和分片算法,由於分片算法的獨立性,將其獨立抽離。真正可用於分片操作的是分片鍵 + 分片算法,也就是分片策略。目前提供5種分片策略。
(1)標準分片策略
對應StandardShardingStrategy。提供對SQL語句中的=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持單分片鍵,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片算法。PreciseShardingAlgorithm是必選的,用於處理=和IN的分片。RangeShardingAlgorithm是可選的,用於處理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND將按照全庫路由處理。
public final class StandardShardingStrategy implements ShardingStrategy {
//分片鍵 支支持單分片鍵
private final String shardingColumn;
//精確分片算法
private final PreciseShardingAlgorithm preciseShardingAlgorithm;
//範圍分片算法
private final RangeShardingAlgorithm rangeShardingAlgorithm;
//
public StandardShardingStrategy(final StandardShardingStrategyConfiguration standardShardingStrategyConfig) {
//校驗分片鍵 不能爲空
Preconditions.checkNotNull(standardShardingStrategyConfig.getShardingColumn(), "Sharding column cannot be null.");
//校驗精確分片算法,不能爲空
Preconditions.checkNotNull(standardShardingStrategyConfig.getPreciseShardingAlgorithm(), "precise sharding algorithm cannot be null.");
//初始化分片策略的屬性
shardingColumn = standardShardingStrategyConfig.getShardingColumn();
preciseShardingAlgorithm = standardShardingStrategyConfig.getPreciseShardingAlgorithm();
//範圍分片算法可以爲空
rangeShardingAlgorithm = standardShardingStrategyConfig.getRangeShardingAlgorithm();
}
//執行分片
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue> shardingValues) {
//ShardingValue 提供獲取邏輯表和分片鍵方法
ShardingValue shardingValue = shardingValues.iterator().next();
//判斷ShardingValue 分片操作是精確分片還是範圍分片,從而執行相應的算法 ;ListShardingValue包含邏輯表、分片鍵、精確匹配值集合
Collection<String> shardingResult = shardingValue instanceof ListShardingValue
? doSharding(availableTargetNames, (ListShardingValue) shardingValue) : doSharding(availableTargetNames, (RangeShardingValue) shardingValue);
Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.addAll(shardingResult);
return result;
}
//範圍分片算法
@SuppressWarnings("unchecked")
private Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<?> shardingValue) {
//如果範圍分片算法爲空
if (null == rangeShardingAlgorithm) {
throw new UnsupportedOperationException("Cannot find range sharding strategy in sharding rule.");
}
return rangeShardingAlgorithm.doSharding(availableTargetNames, shardingValue);
}
//精確分片算法
@SuppressWarnings("unchecked")
private Collection<String> doSharding(final Collection<String> availableTargetNames, final ListShardingValue<?> shardingValue) {
Collection<String> result = new LinkedList<>();
for (PreciseShardingValue<?> each : transferToPreciseShardingValues(shardingValue)) {
String target = preciseShardingAlgorithm.doSharding(availableTargetNames, each);
if (null != target) {
result.add(target);
}
}
return result;
}
//將精確匹配值集合進行轉換爲精確匹配值
@SuppressWarnings("unchecked")
private List<PreciseShardingValue> transferToPreciseShardingValues(final ListShardingValue<?> shardingValue) {
List<PreciseShardingValue> result = new ArrayList<>(shardingValue.getValues().size());
for (Comparable<?> each : shardingValue.getValues()) {
result.add(new PreciseShardingValue(shardingValue.getLogicTableName(), shardingValue.getColumnName(), each));
}
return result;
}
//獲取分片鍵
@Override
public Collection<String> getShardingColumns() {
//String.CASE_INSENSITIVE_ORDER String排序與字母大小寫無關
Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.add(shardingColumn);
return result;
}
}
(2)複合分片策略
對應ComplexShardingStrategy。複合分片策略。提供對SQL語句中的=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片鍵,由於多分片鍵之間的關係複雜,因此並未進行過多的封裝,而是直接將分片鍵值組合以及分片操作符透傳至分片算法,完全由應用開發者實現,提供最大的靈活度。
public final class ComplexShardingStrategy implements ShardingStrategy {
//支持多分片鍵 集合存儲分片鍵
@Getter
private final Collection<String> shardingColumns;
//複合分片算法
private final ComplexKeysShardingAlgorithm shardingAlgorithm;
public ComplexShardingStrategy(final ComplexShardingStrategyConfiguration complexShardingStrategyConfig) {
Preconditions.checkNotNull(complexShardingStrategyConfig.getShardingColumns(), "Sharding columns cannot be null.");
Preconditions.checkNotNull(complexShardingStrategyConfig.getShardingAlgorithm(), "Sharding algorithm cannot be null.");
shardingColumns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
shardingColumns.addAll(StringUtil.splitWithComma(complexShardingStrategyConfig.getShardingColumns()));
shardingAlgorithm = complexShardingStrategyConfig.getShardingAlgorithm();
}
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue> shardingValues) {
Collection<String> shardingResult = shardingAlgorithm.doSharding(availableTargetNames, shardingValues);
Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.addAll(shardingResult);
return result;
}
}
(3)行表達式分片策略
對應InlineShardingStrategy。使用Groovy的表達式,提供對SQL語句中的=和IN的分片操作支持,只支持單分片鍵。對於簡單的分片算法,可以通過簡單的配置使用,從而避免繁瑣的Java代碼開發,如: t_user_$->{u_id % 8} 表示t_user表根據u_id模8,而分成8張表,表名稱爲t_user_0到t_user_7。
public final class InlineShardingStrategy implements ShardingStrategy {
private final String shardingColumn;
//表示Groovy中的任何閉包對象
private final Closure<?> closure;
public InlineShardingStrategy(final InlineShardingStrategyConfiguration inlineShardingStrategyConfig) {
Preconditions.checkNotNull(inlineShardingStrategyConfig.getShardingColumn(), "Sharding column cannot be null.");
Preconditions.checkNotNull(inlineShardingStrategyConfig.getAlgorithmExpression(), "Sharding algorithm expression cannot be null.");
shardingColumn = inlineShardingStrategyConfig.getShardingColumn();
//分片Groovy表達式
String algorithmExpression = InlineExpressionParser.handlePlaceHolder(inlineShardingStrategyConfig.getAlgorithmExpression().trim());
closure = new InlineExpressionParser(algorithmExpression).evaluateClosure();
}
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue> shardingValues) {
ShardingValue shardingValue = shardingValues.iterator().next();
//判斷是否是範圍分片
Preconditions.checkState(shardingValue instanceof ListShardingValue, "Inline strategy cannot support range sharding.");
Collection<String> shardingResult = doSharding((ListShardingValue) shardingValue);
Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.addAll(shardingResult);
return result;
}
//與標準分片策略中的實現相同,不同的是需要通過Groovy進行解析出最終的結果
private Collection<String> doSharding(final ListShardingValue shardingValue) {
Collection<String> result = new LinkedList<>();
for (PreciseShardingValue<?> each : transferToPreciseShardingValues(shardingValue)) {
result.add(execute(each));
}
return result;
}
@SuppressWarnings("unchecked")
private List<PreciseShardingValue> transferToPreciseShardingValues(final ListShardingValue<?> shardingValue) {
List<PreciseShardingValue> result = new ArrayList<>(shardingValue.getValues().size());
for (Comparable<?> each : shardingValue.getValues()) {
result.add(new PreciseShardingValue(shardingValue.getLogicTableName(), shardingValue.getColumnName(), each));
}
return result;
}
//通過Closure解析
private String execute(final PreciseShardingValue shardingValue) {
Closure<?> result = closure.rehydrate(new Expando(), null, null);
result.setResolveStrategy(Closure.DELEGATE_ONLY);
result.setProperty(shardingValue.getColumnName(), shardingValue.getValue());
return result.call().toString();
}
@Override
public Collection<String> getShardingColumns() {
Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.add(shardingColumn);
return result;
}
}
(4)Hint分片策略
對應HintShardingStrategy。通過Hint而非SQL解析的方式分片的策略。
public final class HintShardingStrategy implements ShardingStrategy {
//支持多分片鍵
@Getter
private final Collection<String> shardingColumns;
private final HintShardingAlgorithm shardingAlgorithm;
public HintShardingStrategy(final HintShardingStrategyConfiguration hintShardingStrategyConfig) {
Preconditions.checkNotNull(hintShardingStrategyConfig.getShardingAlgorithm(), "Sharding algorithm cannot be null.");
shardingColumns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
shardingAlgorithm = hintShardingStrategyConfig.getShardingAlgorithm();
}
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue> shardingValues) {
Collection<String> shardingResult = shardingAlgorithm.doSharding(availableTargetNames, shardingValues.iterator().next());
Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.addAll(shardingResult);
return result;
}
}
(5)不分片策略
對應NoneShardingStrategy。不分片的策略。
4 SQL Hint
對於分片字段非SQL決定,而由其他外置條件決定的場景,可使用SQL Hint靈活的注入分片字段;