sharding sphere 4.0.0-RC1版本 按年分表(自動建表)


1. sharding sphere 4.0.0-RC1版本 按年分表(自動建表)

1.1. 概述

上篇文章留了個坑,sharding sphere本身沒有提供自動建表功能,但我想了想,我們可以繞過它本身的設定,它本身的數據分片是通過分片算法實現,如下繼承一些接口PreciseShardingAlgorithmRangeShardingAlgorithm等,在范圍查詢的時候,原本我們需要從availableTargetNames參數去判斷已存在的表,從而做到不查不存在的表,插入時也是同樣的道理

但是事實上我們可以不需要使用availableTargetNames參數,在系統初始化的時候自行去查詢已存在的表再緩存起來,當然過程中我也踩了些坑,因為LogShardingAlgorithm的加載過程和我讀數據庫的順序不好控制,理論上我可以隨時連接數據庫讀,但我又需要讀到spring加載的配置環境再決定連哪個數據庫,不斷的測試后還是不好安排,最后采取了如下的方式,在第一次調用分片算法的時候讀取並緩存表

這樣做后實現的效果就是在做插入數據的時候,我判斷日期為2020年的表是否在緩存中,在則說明數據庫存在該表,否則我先創建該表,再把該表加入緩存;而做范圍查詢的時候,我們容易請求參數超范圍,則從緩存中的表挑選,這些表才是存在的,比如你數據庫存在2018,2019,2020年的表,你查詢條件是2017~2021,那么也只會查18,19,20三張表

/**
 * @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_";

    private Boolean isLoad = false;

    @Override
    public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {
        if (!isLoad) {
            tables = DBUtil.getAllSystemLogTable();
            isLoad = true;
        }
        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) {
        if (!isLoad) {
            tables = DBUtil.getAllSystemLogTable();
            isLoad = true;
        }
        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;
    }
}

1.2. 技巧

  1. 這里要讀取system_log_2019,system_log_2020表的表名只需查詢mysql的information_schema.TABLES,如:
select TABLE_NAME from information_schema.`TABLES`
where TABLE_NAME like 'system_log_%'

老梁講Java

歡迎關注公眾號,回復“教學視頻”一起學習進步


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM