亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Sharding-Jdbc自定義復合分片的實現方法

發布時間:2021-07-30 14:33:09 來源:億速云 閱讀:145 作者:chen 欄目:開發技術

這篇文章主要講解了“Sharding-Jdbc自定義復合分片的實現方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Sharding-Jdbc自定義復合分片的實現方法”吧!

目錄
  • Sharding-JDBC的數據分片策略

    • 分片鍵

    • 分片算法

    • 分片策略

    • SQL Hint

  • 實戰–自定義復合分片策略

    • 小結

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

      • 數據源分片策略(DatabaseShardingStrategy)

      • 表分片策略(TableShardingStrategy)

      其中,數據源分片策略表示:數據路由到的物理目標數據源,表分片策略表示數據被路由到的目標表。

      特別的,表分片策略是依賴于數據源分片策略的,也就是說要先分庫再分表,當然也可以只分表。

      Sharding-Jdbc自定義復合分片的實現方法

      Sharding-JDBC的數據分片策略

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

      以下內容引用自官方文檔。官方文檔

      首先介紹四種分片算法。

      通過分片算法將數據分片,支持通過=、BETWEEN和IN分片。
      分片算法需要應用方開發者自行實現,可實現的靈活度非常高。

      目前提供4種分片算法。由于分片算法和業務實現緊密相關,
      因此并未提供內置分片算法,而是通過分片策略將各種場景提煉出來,
      提供更高層級的抽象,并提供接口讓應用開發者自行實現分片算法。

      分片鍵

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

      分片算法

      通過分片算法將數據分片,支持通過=BETWEENIN分片。分片算法需要應用方開發者自行實現,可實現的靈活度非常高。

      目前提供4種分片算法。由于分片算法和業務實現緊密相關,因此并未提供內置分片算法,而是通過分片策略將各種場景提煉出來,提供更高層級的抽象,并提供接口讓應用開發者自行實現分片算法。

      精確分片算法

      對應PreciseShardingAlgorithm,用于處理使用單一鍵作為分片鍵的=與IN進行分片的場景。需要配合StandardShardingStrategy使用。

      范圍分片算法

      對應RangeShardingAlgorithm,用于處理使用單一鍵作為分片鍵的BETWEEN AND進行分片的場景。需要配合StandardShardingStrategy使用。

      復合分片算法

      對應ComplexKeysShardingAlgorithm,用于處理使用多鍵作為分片鍵進行分片的場景,包含多個分片鍵的邏輯較復雜,需要應用開發者自行處理其中的復雜度。需要配合ComplexShardingStrategy使用。

      Hint分片算法

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

      分片策略

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

      標準分片策略

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

      復合分片策略

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

      行表達式分片策略

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

      Hint分片策略

      對應HintShardingStrategy。通過Hint而非SQL解析的方式分片的策略。

      不分片策略

      對應NoneShardingStrategy。不分片的策略。

      SQL Hint

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

      實戰–自定義復合分片策略

      由于目的為貼近實戰,因此著重講解如何實現復雜分片策略,即實現ComplexShardingStrategy接口定制生產可用的分片策略。

      AdminIdShardingAlgorithm 復合分片算法代碼如下:

      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;
          }
      }

      核心邏輯解析

      梳理一下邏輯,首先介紹一下該方法的入參

      參數名                                         解釋

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

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

      該方法返回值為

      參數名                                                 解釋

      Collection<String>      分片結果,可以是目標數據源,也可以是目標數據表,此處為數據源

      接著回來看業務邏輯,偽代碼如下

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

      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"]}]

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

      完整的邏輯流程如下:

      • 定義一個集合用于放置最終匹配好的路由數據源,接著對shardingValues進行遍歷,目的為至少命中一個路由鍵

      • 遍歷shardingValues循環體中,打印了當前循環的shardingValue,即實際的分片鍵的數值,如:訂單號、用戶id等。通過getIndex方法,獲取該分片鍵值中包含的物理數據源索引

      • 接著遍歷數據源列表availableTargetNames,截取當前循環對應availableTargetName的索引值,(eg: ds0則取0,ds1則取1…以此類推)將該配置的物理數據源索引與 第2步 中解析到的數據源路由索引進行比較,兩者相等則表名我們期望將該數據路由到該匹配到的數據源。

      • 執行這個過程,直到匹配到一個路由鍵則停止循環,之所以這么做是因為我們是復合分片,至少要匹配到一個路由規則,才能停止循環,最終將路由到的物理數據源(ds0/ds1/ds2/ds3)通過add方法添加到事先定義好的集合中并返回給框架。

      • 邏輯結束。

      感謝各位的閱讀,以上就是“Sharding-Jdbc自定義復合分片的實現方法”的內容了,經過本文的學習后,相信大家對Sharding-Jdbc自定義復合分片的實現方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

      向AI問一下細節

      免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

      AI

      凤翔县| 锡林浩特市| 天门市| 新巴尔虎左旗| 南阳市| 三门县| 太仓市| 陵川县| 图片| 安阳市| 新田县| 呼伦贝尔市| 娱乐| 江北区| 呼玛县| 巴青县| 新晃| 敖汉旗| 永春县| 昭平县| 林芝县| 河东区| 农安县| 如东县| 无极县| 论坛| 平安县| 金昌市| 运城市| 丹东市| 宜兴市| 珲春市| 四子王旗| 玉屏| 静宁县| 洛扎县| 沂水县| 武冈市| 普定县| 潮安县| 乡城县|