1. sharding sphere 4.0.0-RC1版本 按年分表(後續優化)
1.1. 概述
關於上一篇中LogShardingAlgorithm
的tables
,我原先是在第一次調用的時候初始化,這樣做雖然能實現功能,但每次調用都會走這個if判斷,雖然性能損耗不大,但我覺得這不是業務應該走的邏輯順序,我的理想是在LogShardingAlgorithm
被實例化後去自動初始化tables
現在面對的問題是LogShardingAlgorithm
的實例化是在Spring初始化中間執行的,且它本身的創建不是通過Spring的@Component
等註解生成,而是通過反射實例化。若在實例化剛開始,也就是構造方法執行的時候執行初始化,那時候applicationContext
還沒有初始化完畢,拿不到環境參數,連Datasource
也還沒開始初始化
1.2. 解決方法
經過改造後,代碼如下,單獨拎出一個初始化方法,在類對象實例化後調用
/**
* @author: laoliangliang
* @description: 日誌分片
* @create: 2020/1/2 10:19
**/
@Slf4j
public class LogShardingAlgorithm implements PreciseShardingAlgorithm, RangeShardingAlgorithm<Integer> {
/**
* 緩存存在的表
*/
private List<String> tables;
private final String systemLogHead = "system_log_";
public void init(){
tables = DBUtil.getAllSystemLogTable();
}
@Override
public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {
String target = shardingValue.getValue().toString();
String year = target.substring(target.lastIndexOf("_") 1, target.lastIndexOf("_") 5);
if (!tables.contains(systemLogHead year)) {
DBUtil.createLogTable(year);
tables.add(year);
}
return shardingValue.getLogicTableName() "_" year;
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Integer> shardingValue) {
Collection<String> availables = new ArrayList<>();
Range valueRange = shardingValue.getValueRange();
for (String target : tables) {
Integer shardValue = Integer.parseInt(target.substring(target.lastIndexOf("_") 1, target.lastIndexOf("_") 5));
if (valueRange.hasLowerBound()) {
String lowerStr = valueRange.lowerEndpoint().toString();
Integer start = Integer.parseInt(lowerStr.substring(0, 4));
if (start - shardValue > 0) {
continue;
}
}
if (valueRange.hasUpperBound()) {
String upperStr = valueRange.upperEndpoint().toString();
Integer end = Integer.parseInt(upperStr.substring(0, 4));
if (end - shardValue < 0) {
continue;
}
}
availables.add(target);
}
return availables;
}
}
其中init
方法通過另一個類實例化完成後調用,難點在於如何拿到該實例化的LogShardingAlgorithm
import cn.hutool.core.util.ReflectUtil;
import com.google.common.base.Optional;
import com.onegene.platform.system.log.LogShardingAlgorithm;
import org.apache.shardingsphere.core.rule.ShardingRule;
import org.apache.shardingsphere.core.rule.TableRule;
import org.apache.shardingsphere.core.strategy.route.ShardingStrategy;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.ShardingContext;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
/**
* @author: laoliangliang
* @description:
* @create: 2020/1/18 8:29
**/
@Component
public class StartupConfig {
@Autowired
private DataSource dataSource;
@PostConstruct
public void init() {
this.loadLogInit();
}
private void loadLogInit() {
if (dataSource instanceof ShardingDataSource) {
ShardingDataSource sds = (ShardingDataSource) dataSource;
ShardingContext shardingContext = sds.getShardingContext();
ShardingRule shardingRule = shardingContext.getShardingRule();
Optional<TableRule> systemLog = shardingRule.findTableRule("system_log");
TableRule tableRule = systemLog.orNull();
if (tableRule != null) {
ShardingStrategy tableShardingStrategy = tableRule.getTableShardingStrategy();
LogShardingAlgorithm preciseShardingAlgorithm = (LogShardingAlgorithm) ReflectUtil.getFieldValue(tableShardingStrategy, "preciseShardingAlgorithm");
LogShardingAlgorithm rangeShardingAlgorithm = (LogShardingAlgorithm) ReflectUtil.getFieldValue(tableShardingStrategy, "rangeShardingAlgorithm");
preciseShardingAlgorithm.init();
rangeShardingAlgorithm.init();
}
}
}
}
1.3. 總結
通過查看源碼可以知道,它最後把LogShardingAlgorithm
實例化的對象放入了ShardingDataSource
,那我們就要從裏面把它取出來,若它正常沒提供get方法,那我們就用反射硬把它取出來
通過上述代碼可以看出,範圍分片和精確分片需要實例化兩個類,我想是否可以合到一個類,網上也找了一下,發現有的版本使用ComplexKeysShardingAlgorithm
算法是可以同時實現範圍和精確分片查詢的,但經過我實際測試,現在的4.0.0版本不行,原因在於以下代碼,此爲複雜分片源碼
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(Splitter.on(",").trimResults().splitToList(complexShardingStrategyConfig.getShardingColumns()));
shardingAlgorithm = complexShardingStrategyConfig.getShardingAlgorithm();
}
@SuppressWarnings("unchecked")
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<RouteValue> shardingValues) {
Map<String, Collection<Comparable<?>>> columnShardingValues = new HashMap<>(shardingValues.size(), 1);
String logicTableName = "";
for (RouteValue each : shardingValues) {
// 重點這裏他把each的值強行轉化成了ListRouteValue而範圍查詢對應的爲BetweenRouteValue,所以在源碼級別就被卡死了,除非重寫策略,否則這個已經不能像以前那樣用了
columnShardingValues.put(each.getColumnName(), ((ListRouteValue) each).getValues());
logicTableName = each.getTableName();
}
Collection<String> shardingResult = shardingAlgorithm.doSharding(availableTargetNames, new ComplexKeysShardingValue(logicTableName, columnShardingValues));
Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.addAll(shardingResult);
return result;
}
}
歡迎關注公衆號,回覆“教學視頻”一起學習進步