最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Sharding-Jdbc 自定義復(fù)合分片的實(shí)現(xiàn)(分庫分表)

 更新時(shí)間:2021年07月30日 11:59:37   作者:如.若  
本文主要介紹了Sharding-Jdbc 自定義復(fù)合分片的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

Sharding-JDBC中的分片策略有兩個(gè)維度,分別是:

  • 數(shù)據(jù)源分片策略(DatabaseShardingStrategy)
  • 表分片策略(TableShardingStrategy)

其中,數(shù)據(jù)源分片策略表示:數(shù)據(jù)路由到的物理目標(biāo)數(shù)據(jù)源,表分片策略表示數(shù)據(jù)被路由到的目標(biāo)表。

特別的,表分片策略是依賴于數(shù)據(jù)源分片策略的,也就是說要先分庫再分表,當(dāng)然也可以只分表。

Sharding-JDBC的數(shù)據(jù)分片策略

Sharding-JDBC的分片策略包含了分片鍵和分片算法。由于分片算法與業(yè)務(wù)實(shí)現(xiàn)緊密相關(guān),因此Sharding-JDBC沒有提供內(nèi)置的分片算法,而是通過分片策略將各種場景提煉出來,提供了高層級的抽象,通過提供接口讓開發(fā)者自行實(shí)現(xiàn)分片算法。

以下內(nèi)容引用自官方文檔。官方文檔

首先介紹四種分片算法。

通過分片算法將數(shù)據(jù)分片,支持通過=、BETWEEN和IN分片。
分片算法需要應(yīng)用方開發(fā)者自行實(shí)現(xiàn),可實(shí)現(xiàn)的靈活度非常高。

目前提供4種分片算法。由于分片算法和業(yè)務(wù)實(shí)現(xiàn)緊密相關(guān),
因此并未提供內(nèi)置分片算法,而是通過分片策略將各種場景提煉出來,
提供更高層級的抽象,并提供接口讓應(yīng)用開發(fā)者自行實(shí)現(xiàn)分片算法。

分片鍵

用于分片的數(shù)據(jù)庫字段,是將數(shù)據(jù)庫(表)水平拆分的關(guān)鍵字段。例:將訂單表中的訂單主鍵的尾數(shù)取模分片,則訂單主鍵為分片字段。 SQL中如果無分片字段,將執(zhí)行全路由,性能較差。 除了對單分片字段的支持,ShardingSphere也支持根據(jù)多個(gè)字段進(jìn)行分片。

分片算法

通過分片算法將數(shù)據(jù)分片,支持通過=、BETWEENIN分片。分片算法需要應(yīng)用方開發(fā)者自行實(shí)現(xiàn),可實(shí)現(xiàn)的靈活度非常高。

目前提供4種分片算法。由于分片算法和業(yè)務(wù)實(shí)現(xiàn)緊密相關(guān),因此并未提供內(nèi)置分片算法,而是通過分片策略將各種場景提煉出來,提供更高層級的抽象,并提供接口讓應(yīng)用開發(fā)者自行實(shí)現(xiàn)分片算法。

精確分片算法

對應(yīng)PreciseShardingAlgorithm,用于處理使用單一鍵作為分片鍵的=與IN進(jìn)行分片的場景。需要配合StandardShardingStrategy使用。

范圍分片算法

對應(yīng)RangeShardingAlgorithm,用于處理使用單一鍵作為分片鍵的BETWEEN AND進(jìn)行分片的場景。需要配合StandardShardingStrategy使用。

復(fù)合分片算法

對應(yīng)ComplexKeysShardingAlgorithm,用于處理使用多鍵作為分片鍵進(jìn)行分片的場景,包含多個(gè)分片鍵的邏輯較復(fù)雜,需要應(yīng)用開發(fā)者自行處理其中的復(fù)雜度。需要配合ComplexShardingStrategy使用。

Hint分片算法

對應(yīng)HintShardingAlgorithm,用于處理使用Hint行分片的場景。需要配合HintShardingStrategy使用。

分片策略

包含分片鍵和分片算法,由于分片算法的獨(dú)立性,將其獨(dú)立抽離。真正可用于分片操作的是分片鍵 + 分片算法,也就是分片策略。目前提供5種分片策略。

標(biāo)準(zhǔn)分片策略

對應(yīng)StandardShardingStrategy。提供對SQL語句中的=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持單分片鍵,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個(gè)分片算法。PreciseShardingAlgorithm是必選的,用于處理=和IN的分片。RangeShardingAlgorithm是可選的,用于處理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND將按照全庫路由處理。

復(fù)合分片策略

對應(yīng)ComplexShardingStrategy。復(fù)合分片策略。提供對SQL語句中的=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片鍵,由于多分片鍵之間的關(guān)系復(fù)雜,因此并未進(jìn)行過多的封裝,而是直接將分片鍵值組合以及分片操作符透傳至分片算法,完全由應(yīng)用開發(fā)者實(shí)現(xiàn),提供最大的靈活度。

行表達(dá)式分片策略

對應(yīng)InlineShardingStrategy。使用Groovy的表達(dá)式,提供對SQL語句中的=和IN的分片操作支持,只支持單分片鍵。對于簡單的分片算法,可以通過簡單的配置使用,從而避免繁瑣的Java代碼開發(fā),如:t_user_$->{u_id % 8}表示t_user表根據(jù)u_id模8,而分成8張表,表名稱為t_user_0t_user_7。

Hint分片策略

對應(yīng)HintShardingStrategy。通過Hint而非SQL解析的方式分片的策略。

不分片策略

對應(yīng)NoneShardingStrategy。不分片的策略。

SQL Hint

對于分片字段非SQL決定,而由其他外置條件決定的場景,可使用SQL Hint靈活的注入分片字段。例:內(nèi)部系統(tǒng),按照員工登錄主鍵分庫,而數(shù)據(jù)庫中并無此字段。SQL Hint支持通過Java API和SQL注釋(待實(shí)現(xiàn))兩種方式使用。

實(shí)戰(zhàn)–自定義復(fù)合分片策略

由于目的為貼近實(shí)戰(zhàn),因此著重講解如何實(shí)現(xiàn)復(fù)雜分片策略,即實(shí)現(xiàn)ComplexShardingStrategy接口定制生產(chǎn)可用的分片策略。

AdminIdShardingAlgorithm 復(fù)合分片算法代碼如下:

import com.google.common.collect.Range;
import io.shardingjdbc.core.api.algorithm.sharding.ListShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.RangeShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.ShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
 
import java.util.*;
 
/**
 */
public class AdminIdShardingAlgorithm implements ComplexKeysShardingAlgorithm {
 
    private Logger logger = Logger.getLogger(getClass());
 
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue> shardingValues) {
        Collection<String> routTables = new HashSet<String>();
        if (shardingValues != null) {
            for (ShardingValue shardingValue : shardingValues) {
 
                // eq in 條件
                if (shardingValue instanceof ListShardingValue) {
                    ListShardingValue listShardingValue = (ListShardingValue) shardingValue;
                    Collection<Comparable> values = listShardingValue.getValues();
                    if (values != null) {
                        Iterator<Comparable> it = values.iterator();
                        while (it.hasNext()) {
                            Comparable value = it.next();
                            String routTable = getRoutTable(shardingValue.getLogicTableName(), value);
                            if (StringUtils.isNotBlank(routTable)) {
                                routTables.add(routTable);
                            }
                        }
                    }
 
                    // eq 條件
                } else if (shardingValue instanceof PreciseShardingValue) {
                    PreciseShardingValue preciseShardingValue = (PreciseShardingValue) shardingValue;
 
                    Comparable value = preciseShardingValue.getValue();
                    String routTable = getRoutTable(shardingValue.getLogicTableName(), value);
                    if (StringUtils.isNotBlank(routTable)) {
                        routTables.add(routTable);
                    }
                    // between 條件
                } else if (shardingValue instanceof RangeShardingValue) {
                    RangeShardingValue rangeShardingValue = (RangeShardingValue) shardingValue;
                    Range<Comparable> valueRange = rangeShardingValue.getValueRange();
                    Comparable lowerEnd = valueRange.lowerEndpoint();
                    Comparable upperEnd = valueRange.upperEndpoint();
 
                    Collection<String> tables = getRoutTables(shardingValue.getLogicTableName(), lowerEnd, upperEnd);
                    if (tables != null && tables.size() > 0) {
                        routTables.addAll(tables);
                    }
                }
 
                if (routTables != null && routTables.size() > 0) {
                    return routTables;
                }
            }
        }
 
        throw new UnsupportedOperationException();

    }
 
    private String getRoutTable(String logicTable, Comparable keyValue) {
        Map<String, List<KeyShardingRange>> keyRangeMap = KeyShardingRangeConfig.getKeyRangeMap();
 
        List<KeyShardingRange> keyShardingRanges = keyRangeMap.get(KeyShardingRangeConfig.SHARDING_ID_KEY);
 
        if (keyValue != null && keyShardingRanges != null) {
            if (keyValue instanceof Integer) {
                keyValue = Long.valueOf(((Integer) keyValue).intValue());
            }
            for (KeyShardingRange range : keyShardingRanges) {
                if (keyValue.compareTo(range.getMin()) >= 0 && keyValue.compareTo(range.getMax()) <= 0) {
                    return logicTable + range.getTableKey();
                }
            }
        }
        return null;
    }
    private Collection<String> getRoutTables(String logicTable, Comparable lowerEnd, Comparable upperEnd) {
        Map<String, List<KeyShardingRange>> keyRangeMap = KeyShardingRangeConfig.getKeyRangeMap();
 
        List<KeyShardingRange> keyShardingRanges = keyRangeMap.get(KeyShardingRangeConfig.SHARDING_CONTENT_ID_KEY);
        Set<String> routTables = new HashSet<String>();
        if (lowerEnd != null && upperEnd != null && keyShardingRanges != null) {
            if (lowerEnd instanceof Integer) {
                lowerEnd = Long.valueOf(((Integer) lowerEnd).intValue());
            }
 
            if (upperEnd instanceof Integer) {
                upperEnd = Long.valueOf(((Integer) upperEnd).intValue());
            }
            boolean start = false;
            for (KeyShardingRange range : keyShardingRanges) {
                if (lowerEnd.compareTo(range.getMin()) >= 0 && lowerEnd.compareTo(range.getMax()) <= 0) {
                    start = true;
                }
                if (start) {
                    routTables.add(logicTable + range.getTableKey());
                }
                if (upperEnd.compareTo(range.getMin()) >= 0 && upperEnd.compareTo(range.getMax()) <= 0) {
                    break;
                }
            }
        }
        return routTables;
    }
}

范圍 map 如下:

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 分片鍵分布配置
 */
public class KeyShardingRangeConfig {
 
    private static Map<String, List<KeyShardingRange>> keyRangeMap = new LinkedHashMap<String, List<KeyShardingRange>>();
 
    public static final String SHARDING_ORDER_ID_KEY = "id";
 
    public static final String SHARDING_USER_ID_KEY = "adminId";
 
    public static final String SHARDING_DATE_KEY = "createTime";
 
    static {
        List<KeyShardingRange> idRanges = new ArrayList<KeyShardingRange>();
        idRanges.add(new KeyShardingRange(0, "_0", 0L, 4000000L));
        idRanges.add(new KeyShardingRange(1, "_1", 4000001L, 8000000L));
        idRanges.add(new KeyShardingRange(2, "_2", 8000001L, 12000000L));
        idRanges.add(new KeyShardingRange(3, "_3", 12000001L, 16000000L));
        idRanges.add(new KeyShardingRange(4, "_4", 16000001L, 2000000L));
        keyRangeMap.put(SHARDING_ID_KEY, idRanges);
 
        List<KeyShardingRange> contentIdRanges = new ArrayList<KeyShardingRange>();
        contentIdRanges.add(new KeyShardingRange(0, "_0", 0L, 4000000L));
        contentIdRanges.add(new KeyShardingRange(1, "_1", 4000001L, 8000000L));
        contentIdRanges.add(new KeyShardingRange(2, "_2", 8000001L, 12000000L));
        contentIdRanges.add(new KeyShardingRange(3, "_3", 12000001L, 16000000L));
        contentIdRanges.add(new KeyShardingRange(4, "_4", 16000001L, 2000000L));
        keyRangeMap.put(SHARDING_CONTENT_ID_KEY, contentIdRanges);
 
        List<KeyShardingRange> timeRanges = new ArrayList<KeyShardingRange>();
        timeRanges.add(new KeyShardingRange("_0", 20170701L, 20171231L));
        timeRanges.add(new KeyShardingRange("_1", 20180101L, 20180630L));
        timeRanges.add(new KeyShardingRange("_2", 20180701L, 20181231L));
        timeRanges.add(new KeyShardingRange("_3", 20190101L, 20190630L));
        timeRanges.add(new KeyShardingRange("_4", 20190701L, 20191231L));
        keyRangeMap.put(SHARDING_DATE_KEY, timeRanges);
    }
 
    public static Map<String, List<KeyShardingRange>> getKeyRangeMap() {
        return keyRangeMap;
    }
}

核心邏輯解析

梳理一下邏輯,首先介紹一下該方法的入?yún)?/p>

參數(shù)名                                         解釋

availableTargetNames     有效的物理數(shù)據(jù)源,即配置文件中的 t_order_0,t_order_1,t_order_2,t_order_3

shardingValues             分片屬性,如:{“columnName”:”order_id”,”logicTableName”:”t_order”,”values”:[“UD020003011903261545436593200002”]} ,包含:分片列名,邏輯表名,當(dāng)前列的具體分片值

該方法返回值為

參數(shù)名                                                 解釋

Collection<String>      分片結(jié)果,可以是目標(biāo)數(shù)據(jù)源,也可以是目標(biāo)數(shù)據(jù)表,此處為數(shù)據(jù)源

接著回來看業(yè)務(wù)邏輯,偽代碼如下

首先打印了一下數(shù)據(jù)源集合 availableTargetNames 以及 分片屬性 shardingValues的值,執(zhí)行測試用例后,日志輸出為:

availableTargetNames:["t_order_0","t_order_1","t_order_2","t_order_3"],
shardingValues:[{"columnName":"user_id","logicTableName":"t_order","values":["UD020003011903261545436593200002"]},
                {"columnName":"order_id","logicTableName":"t_order","values":["OD000000011903261545475143200001"]}]

從日志可以看出,我們可以在該路由方法中取到配置時(shí)的物理數(shù)據(jù)源列表,以及在運(yùn)行時(shí)獲取本次執(zhí)行時(shí)的路由屬性及其值

完整的邏輯流程如下:

  • 定義一個(gè)集合用于放置最終匹配好的路由數(shù)據(jù)源,接著對shardingValues進(jìn)行遍歷,目的為至少命中一個(gè)路由鍵
  • 遍歷shardingValues循環(huán)體中,打印了當(dāng)前循環(huán)的shardingValue,即實(shí)際的分片鍵的數(shù)值,如:訂單號、用戶id等。通過getIndex方法,獲取該分片鍵值中包含的物理數(shù)據(jù)源索引
  • 接著遍歷數(shù)據(jù)源列表availableTargetNames,截取當(dāng)前循環(huán)對應(yīng)availableTargetName的索引值,(eg: ds0則取0,ds1則取1…以此類推)將該配置的物理數(shù)據(jù)源索引與 第2步 中解析到的數(shù)據(jù)源路由索引進(jìn)行比較,兩者相等則表名我們期望將該數(shù)據(jù)路由到該匹配到的數(shù)據(jù)源。
  • 執(zhí)行這個(gè)過程,直到匹配到一個(gè)路由鍵則停止循環(huán),之所以這么做是因?yàn)槲覀兪菑?fù)合分片,至少要匹配到一個(gè)路由規(guī)則,才能停止循環(huán),最終將路由到的物理數(shù)據(jù)源(ds0/ds1/ds2/ds3)通過add方法添加到事先定義好的集合中并返回給框架。
  • 邏輯結(jié)束。

小結(jié)

本文中,基本完成了Sharding-JDBC中復(fù)合分片路由算法的自定義實(shí)現(xiàn),并經(jīng)過測試驗(yàn)證符合預(yù)期,該實(shí)現(xiàn)方案在生產(chǎn)上已經(jīng)經(jīng)歷過考驗(yàn)。定義分片路由策略的核心還是要熟悉ComplexKeysShardingAlgorithm,對如何解析 doSharding(CollectionavailableTargetNames, CollectionshardingValues)的參數(shù)有明確的認(rèn)識,最簡單的方法就是實(shí)際打印一下參數(shù),相信會讓你更加直觀的感受到作者優(yōu)良的接口設(shè)計(jì)能力,站在巨人的肩膀上我們能看到更遠(yuǎn)。

到此這篇關(guān)于Sharding-Jdbc 自定義復(fù)合分片的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Sharding-Jdbc 自定義復(fù)合分片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java并發(fā)中線程封閉知識點(diǎn)詳解

    Java并發(fā)中線程封閉知識點(diǎn)詳解

    在本篇文章里我們給大家整理了關(guān)于Java并發(fā)中線程封閉的知識點(diǎn)總結(jié)內(nèi)容,需要的朋友們學(xué)習(xí)參考下。
    2019-07-07
  • Spring Boot集成Sorl搜索客戶端的實(shí)現(xiàn)代碼

    Spring Boot集成Sorl搜索客戶端的實(shí)現(xiàn)代碼

    本篇文章主要介紹了Spring Boot集成Sorl搜索客戶端的實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • Java多線程 線程組原理及實(shí)例詳解

    Java多線程 線程組原理及實(shí)例詳解

    這篇文章主要介紹了Java多線程 線程組原理及實(shí)例詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • feign遠(yuǎn)程調(diào)用無法傳遞對象屬性405的問題

    feign遠(yuǎn)程調(diào)用無法傳遞對象屬性405的問題

    這篇文章主要介紹了feign遠(yuǎn)程調(diào)用無法傳遞對象屬性405的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • java中hashmap容量的初始化實(shí)現(xiàn)

    java中hashmap容量的初始化實(shí)現(xiàn)

    這篇文章主要介紹了java中hashmap容量的初始化實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • JavaWeb Session 會話管理實(shí)例詳解

    JavaWeb Session 會話管理實(shí)例詳解

    這篇文章主要介紹了JavaWeb Session 會話管理的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-09-09
  • Java中的==、equals與hashCode區(qū)別與聯(lián)系最佳實(shí)踐

    Java中的==、equals與hashCode區(qū)別與聯(lián)系最佳實(shí)踐

    在Java開發(fā)中,==、equals和hashCode是三個(gè)高頻出現(xiàn)的概念,也是初學(xué)者最容易混淆的知識點(diǎn),本文將從底層原理出發(fā),全面解析三者的區(qū)別、聯(lián)系及最佳實(shí)踐,幫你徹底理清它們的使用場景,感興趣的朋友一起看看吧
    2025-09-09
  • Java 并行流(parallelStream)的具體使用小結(jié)

    Java 并行流(parallelStream)的具體使用小結(jié)

    parallelStream是Java 8中的一種流處理方式,通過并行流利用多核CPU提高數(shù)據(jù)處理效率,本文主要介紹了Java 并行流(parallelStream)的具體使用小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-11-11
  • 深入理解Java中的HashMap

    深入理解Java中的HashMap

    HashMap是Java程序員使用頻率最高的用于映射(鍵值對)處理的數(shù)據(jù)類型。隨著JDK(Java Developmet Kit)版本的更新,JDK1.8對HashMap底層的實(shí)現(xiàn)進(jìn)行了優(yōu)化,例如引入紅黑樹的數(shù)據(jù)結(jié)構(gòu)和擴(kuò)容的優(yōu)化等。本文將深入探討HashMap的結(jié)構(gòu)實(shí)現(xiàn)和功能原理
    2021-06-06
  • java多線程編程必備volatile與synchronized深入理解

    java多線程編程必備volatile與synchronized深入理解

    這篇文章主要介紹了java多線程編程必備volatile與synchronized的深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04

最新評論

张家港市| 栾川县| 定安县| 海晏县| 桐乡市| 舞阳县| 八宿县| 鱼台县| 油尖旺区| 丰县| 阳谷县| 泾阳县| 南郑县| 安西县| 盐山县| 阿图什市| 五华县| 三原县| 谷城县| 安丘市| 黑龙江省| 安化县| 岳池县| 榆林市| 庐江县| 宣武区| 红桥区| 海口市| 石首市| 喀喇| 广昌县| 内黄县| 特克斯县| 昭平县| 报价| 揭阳市| 高州市| 广昌县| 志丹县| 涟水县| 宁晋县|