<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jinfeng_wang

    G-G-S,D-D-U!

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
    代碼:sharding-jdbc-config-common 目錄
    面臨的問題: select * from a, b where a.user_id =b.user_id  
    在分庫分表的情況下,如何決定一個正確的JDBC DataSource,一個正確的Table Name


    http://dangdangdotcom.github.io/sharding-jdbc/post/user_guide/

    數據庫模式

    本文檔中提供了兩個數據源db0db1,每個數據源之中包含了兩組表t_order_0t_order_1t_order_item_0t_order_item_1。這兩組表的建表語句為:

    CREATE TABLE IF NOT EXISTS `t_order_x` (   `order_id` INT NOT NULL,   `user_id`  INT NOT NULL,   PRIMARY KEY (`order_id`) ); CREATE TABLE IF NOT EXISTS `t_order_item_x` (   `item_id`  INT NOT NULL,   `order_id` INT NOT NULL,   `user_id`  INT NOT NULL,   PRIMARY KEY (`item_id`) ); 

    邏輯表與實際表映射關系

    均勻分布

    數據表在每個數據源內呈現均勻分布的態勢

    db0   ├── t_order_0    └── t_order_1  db1   ├── t_order_0    └── t_order_1 

    表規則可以使用默認的配置

     TableRule orderTableRule = TableRule.builder("t_order").actualTables(Arrays.asList("t_order_0", "t_order_1")).dataSourceRule(dataSourceRule).build(); 

    自定義分布

    數據表呈現有特定規則的分布

    db0   ├── t_order_0    └── t_order_1  db1   ├── t_order_2   ├── t_order_3   └── t_order_4 

    表規則可以指定每張表在數據源中的分布情況

     TableRule orderTableRule = TableRule.builder("t_order").actualTables(Arrays.asList("db0.t_order_0", "db0.t_order_1", "db1.t_order_2", "db1.t_order_3", "db1.t_order_4")).dataSourceRule(dataSourceRule).build(); 

    本教程采用的數據分布例子

    db0   ├── t_order_0               user_id為偶數   order_id為偶數   ├── t_order_1               user_id為偶數   order_id為奇數   ├── t_order_item_0          user_id為偶數   order_id為偶數   └── t_order_item_1          user_id為偶數   order_id為奇數 db1   ├── t_order_0               user_id為奇數   order_id為偶數   ├── t_order_1               user_id為奇數   order_id為奇數   ├── t_order_item_0          user_id為奇數   order_id為偶數   └── t_order_item_1          user_id為奇數   order_id為奇數 

    邏輯表與實際表

    配置分庫分表的目的是將原有一張表的數據分散到不同庫不同表中,且不改變原有SQL語句的情況下來使用這一張表。那么從一張表到多張的映射關系需要使用邏輯表與實際表這兩種概念。下面通過一個例子來解釋一下。假設在使用PreparedStatement訪問數據庫,SQL如下:

    select * from t_order where user_id = ? and order_id = ?; 

    user_id=0order=0時,Sharding-JDBC將會將SQL語句轉換為如下形式:

    select * from db0.t_order_0 where user_id = ? and order_id = ?; 

    其中原始SQL中的t_order就是 邏輯表,而轉換后的db0.t_order_0就是 實際表

    規則配置

    以上分庫分表的形式Sharding-JDBC是通過規則配置來進行的描述的,下面講通過幾個小節來描述規則的詳細配置:

     ShardingRule shardingRule = ShardingRule.builder()         .dataSourceRule(dataSourceRule)         .tableRules(Arrays.asList(orderTableRule, orderItemTableRule))         .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))         .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm())))         .build(); 

    數據源配置

    首先我們來構造DataSourceRule對象,它是來描述數據源的分布規則的。

     DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap); 

    這里構造器需要一個入參:數據源名稱與真實數據源之間的映射關系,這個關系的構造方法如下

    Map<String, DataSource> dataSourceMap = new HashMap<>(2); dataSourceMap.put("ds_0", createDataSource("ds_0")); dataSourceMap.put("ds_1", createDataSource("ds_1")); 

    真實的數據源可以使用任意一種數據庫連接池,這里使用DBCP來舉例

    private static DataSource createDataSource(final String dataSourceName) {     BasicDataSource result = new BasicDataSource();     result.setDriverClassName(com.mysql.jdbc.Driver.class.getName());     result.setUrl(String.format("jdbc:mysql://localhost:3306/%s", dataSourceName));     result.setUsername("root");     result.setPassword("");     return result; } 

    策略配置

    數據源策略與表策略

    策略類圖Sharding-JDBC認為對于分片策略存有兩種維度 - 數據源分片策略DatabaseShardingStrategy:數據被分配的目標數據源 - 表分片策略TableShardingStrategy:數據被分配的目標表,該目標表存在與該數據的目標數據源內。故表分片策略是依賴與數據源分片策略的結果的 這里注意的是兩種策略的API完全相同,以下針對策略API的講解將適用于這兩種策略

    全局默認策略與特定表策略

    策略是作用在特定的表規則上的,數據源策略與表策略與特定表相關

     TableRule orderTableRule = TableRule.builder("t_order")          .actualTables(Arrays.asList("t_order_0", "t_order_1")          .dataSourceRule(dataSourceRule)          .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))          .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm())))          .build(); 

    如果分片規則中的所有表或大部分表的分片策略相同,可以使用默認策略來簡化配置。以下兩種配置是等價的:

      //使用了默認策略配置   TableRule orderTableRule = TableRule.builder("t_order")           .actualTables(Arrays.asList("t_order_0", "t_order_1")           .dataSourceRule(dataSourceRule)           .build();   TableRule orderItemTableRule = TableRule.builder("t_order_item")             .actualTables(Arrays.asList("t_order_item_0", "t_order_item_1")             .dataSourceRule(dataSourceRule)             .build();   ShardingRule shardingRule = ShardingRule.builder()             .dataSourceRule(dataSourceRule)             .tableRules(Arrays.asList(orderTableRule, orderItemTableRule))             .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))             .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm())))             .build(); 
      //未使用默認策略配置   TableRule orderTableRule = TableRule.builder("t_order")           .actualTables(Arrays.asList("t_order_0", "t_order_1")           .dataSourceRule(dataSourceRule)           .build();   TableRule orderItemTableRule = TableRule.builder("t_order_item")             .actualTables(Arrays.asList("t_order_item_0", "t_order_item_1")             .dataSourceRule(dataSourceRule)             .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))             .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm())))             .build();   ShardingRule shardingRule = ShardingRule.builder()             .dataSourceRule(dataSourceRule)             .tableRules(Arrays.asList(orderTableRule, orderItemTableRule))             .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))             .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm())))             .build(); 

    分片鍵

    分片鍵是分片策略的第一個參數。分片鍵表示的是SQL語句中WHERE中的條件列。分片鍵可以配置多個

    • 單分片策略
    new TableShardingStrategy("order_id", new SingleKeyShardingAlgorithm())) 
    • 多分片策略
    new TableShardingStrategy(Arrays.asList("order_id", "order_type", "order_date"), new MultiKeyShardingAlgorithm())) 

    分片算法

    分片算法接口類圖關系如下:

    算法

    綁定表

    綁定表代表一組表,這組表的邏輯表與實際表之間的映射關系是相同的。比如t_ordert_order_item就是這樣一組綁定表關系,它們的分庫與分表策略是完全相同的,那么可以使用它們的表規則將它們配置成綁定表

    new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule)) 

    那么在進行SQL路由時,如果SQL為

    SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=? AND o.order_id=? 

    其中t_order在FROM的最左側,Sharding-JDBC將會以它作為整個綁定表的主表。所有路由計算將會只使用主表的策略,那么t_order_item表的分片計算將會使用t_order的條件。故綁定表之間的分區鍵要完全相同。

    分片算法詳解

    單分片鍵算法與多分片鍵算法

    這兩種算法從名字上就可以知道前者是針對只有一個分片鍵,后者是針對有多個分片鍵的。單分片鍵算法是多分片鍵算法的一種簡便形式,所以完全可以使用多分片算法去替代單分片鍵算法。下面兩種形式是等價的

    new TableShardingStrategy("order_id", new SingleKeyShardingAlgorithm())) new TableShardingStrategy(Arrays.asList("order_id"), new MultiKeyShardingAlgorithm())) 

    同時在算法內部,doSharding等方法的shardingValue入參根據使用算法類型不同而不同 單分片鍵算法,方法簽名

    public String doEqualSharding(final Collection<String> dataSourceNames, final ShardingValue<Integer> shardingValue)  

    多分片鍵算法,方法簽名

    public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue<?>> shardingValues) 

    分片鍵算法類型

    根據數據源策略與表策略、單分片與多分片,這兩種組合,一共產生了4種可供實現的分片算法的接口

    • 單分片鍵數據源分片算法SingleKeyDatabaseShardingAlgorithm
    • 單分片表分片算法SingleKeyTableShardingAlgorithm
    • 多分片鍵數據源分片算法MultipleKeyDatabaseShardingAlgorithm
    • 多分片表分片算法MultipleKeyTableShardingAlgorithm

    單分片鍵算法

    單分片鍵算法需要實現三個方法,下面以”單分片鍵數據源分片算法“舉例

    @Override public String doEqualSharding(final Collection<String> availableTargetNames, final ShardingValue<Integer> shardingValue)  @Override public Collection<String> doInSharding(final Collection<String> availableTargetNames, final ShardingValue<Integer> shardingValue)  @Override public Collection<String> doBetweenSharding(final Collection<String> availableTargetNames, final ShardingValue<Integer> shardingValue) 

    這三種算法作用如下 - doEqualSharding在WHERE使用=作為條件分片鍵。算法中使用shardingValue.getValue()獲取等=后的值 - doInSharding在WHERE使用IN作為條件分片鍵。算法中使用shardingValue.getValues()獲取IN后的值 - doBetweenSharding在WHERE使用BETWEEN作為條件分片鍵。算法中使用shardingValue.getValueRange()獲取BETWEEN后的值

    下面是一個余2的算法的例子,當分片鍵的值除以2余數就是實際表的結尾。注意注釋中提供了一些算法生成SQL的結果,參數tableNames集合中有兩個參數t_order_0t_order_1

     public final class ModuloTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Integer> {          /**     *  select * from t_order from t_order where order_id = 11      *          └── SELECT *  FROM t_order_1 WHERE order_id = 11     *  select * from t_order from t_order where order_id = 44     *          └── SELECT *  FROM t_order_0 WHERE order_id = 44     */     public String doEqualSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {         for (String each : tableNames) {             if (each.endsWith(shardingValue.getValue() % 2 + "")) {                 return each;             }         }         throw new IllegalArgumentException();     }          /**     *  select * from t_order from t_order where order_id in (11,44)       *          ├── SELECT *  FROM t_order_0 WHERE order_id IN (11,44)      *          └── SELECT *  FROM t_order_1 WHERE order_id IN (11,44)      *  select * from t_order from t_order where order_id in (11,13,15)       *          └── SELECT *  FROM t_order_1 WHERE order_id IN (11,13,15)       *  select * from t_order from t_order where order_id in (22,24,26)       *          └──SELECT *  FROM t_order_0 WHERE order_id IN (22,24,26)      */     public Collection<String> doInSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {         Collection<String> result = new LinkedHashSet<>(tableNames.size());         for (Integer value : shardingValue.getValues()) {             for (String tableName : tableNames) {                 if (tableName.endsWith(value % 2 + "")) {                     result.add(tableName);                 }             }         }         return result;     }          /**     *  select * from t_order from t_order where order_id between 10 and 20      *          ├── SELECT *  FROM t_order_0 WHERE order_id BETWEEN 10 AND 20      *          └── SELECT *  FROM t_order_1 WHERE order_id BETWEEN 10 AND 20      */     public Collection<String> doBetweenSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {         Collection<String> result = new LinkedHashSet<>(tableNames.size());         Range<Integer> range = (Range<Integer>) shardingValue.getValueRange();         for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {             for (String each : tableNames) {                 if (each.endsWith(i % 2 + "")) {                     result.add(each);                 }             }         }         return result;     } } 

    多分片鍵算法

    多分片鍵試用于使用場景比較復雜,為了能提供更高的靈活性,故只提供實現一個方法。

    @Override public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue<?>> shardingValues) 

    算法實現的時候根據shardingValue.getType()來獲取條件是=IN或者BETWEEN。然后根據業務進行靈活的實現。

    如果表的數據分布如下

    db0   ├── t_order_00               user_id以a偶數   order_id為偶數   ├── t_order_01               user_id以a偶數   order_id為奇數   ├── t_order_10               user_id以b奇數   order_id為偶數   └── t_order_11               user_id以b奇數   order_id為奇數  

    算法實現如下:

    public final class MultipleKeysModuloTableShardingAlgorithm implements MultipleKeysTableShardingAlgorithm {          @Override     public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue<?>> shardingValues) {         Set<Integer> orderIdValueSet = getShardingValue(shardingValues, "order_id");         Set<Integer> userIdValueSet = getShardingValue(shardingValues, "user_id");              List<String> result = new ArrayList<>();         /*         userIdValueSet[10,11] + orderIdValueSet[101,102] => valueResult[[10,101],[10,102],[11,101],[11,102]]          */         Set<List<Integer>> valueResult = Sets.cartesianProduct(userIdValueSet, orderIdValueSet);         for (List<Integer> value : valueResult) {             String suffix = Joiner.on("").join(value.get(0) % 2, value.get(1) % 2);             for (String tableName : availableTargetNames) {                 if (tableName.endsWith(suffix)) {                     result.add(tableName);                 }             }                  }         return result;     }          private Set<Integer> getShardingValue(final Collection<ShardingValue<?>> shardingValues, final String shardingKey) {         Set<Integer> valueSet = new HashSet<>();         ShardingValue<Integer> shardingValue = null;         for (ShardingValue<?> each : shardingValues) {             if (each.getColumnName().equals(shardingKey)) {                 shardingValue = (ShardingValue<Integer>) each;                 break;             }         }         if (null == shardingValue) {             return valueSet;         }         switch (shardingValue.getType()) {             case SINGLE:                 valueSet.add(shardingValue.getValue());                 break;             case LIST:                 valueSet.addAll(shardingValue.getValues());                 break;             case RANGE:                 for (Integer i = shardingValue.getValueRange().lowerEndpoint(); i <= shardingValue.getValueRange().upperEndpoint(); i++) {                     valueSet.add(i);                 }                 break;             default:                 throw new UnsupportedOperationException();         }         return valueSet;     } } 

    構造ShardingDataSource

    完成規則配置后,我們可以通過ShardingDataSourceFactory工廠得到ShardingDataSource

    DataSource dataSource = new ShardingDataSourceFactory.createDataSource(shardingRule); 

    使用ShardingDataSource

    通過一個例子來看看如何使用該數據源

    String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=? AND o.order_id=?";         try (                 Connection conn = dataSource.getConnection();                 PreparedStatement preparedStatement = conn.prepareStatement(sql);                 ) {             preparedStatement.setInt(1, 10);             preparedStatement.setInt(2, 1001);             ResultSet rs = preparedStatement.executeQuery();             while (rs.next()) {                 System.out.println(rs.getInt(1));                 System.out.println(rs.getInt(2));                 System.out.println(rs.getInt(3));             }             rs.close();         } 

    該數據源與普通數據源完全相同,你可以通過上例的API形式來使用,也可以將其配置在Spring,Hibernate等框架中使用。

    如果希望不依賴于表中的列傳入分片鍵值,參考:基于暗示(Hint)的分片鍵值注冊方法

    posted on 2016-12-28 18:57 jinfeng_wang 閱讀(1772) 評論(0)  編輯  收藏 所屬分類: 2016-Sharding-JDBC

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 久久久久久亚洲av无码蜜芽| 亚洲欧洲国产成人综合在线观看 | 亚洲一区二区三区国产精品无码| 亚洲大尺度无码专区尤物| 亚洲综合AV在线在线播放| 亚洲中文字幕视频国产| 国产综合亚洲专区在线| 国产亚洲精品国看不卡| 国产亚洲欧洲Aⅴ综合一区| 亚洲精品狼友在线播放| 亚洲AV无码乱码在线观看富二代| 亚洲AV日韩精品久久久久| 亚洲黄色片免费看| 亚洲国产中文在线视频| xxx毛茸茸的亚洲| 亚洲精品又粗又大又爽A片| 亚洲大尺度无码无码专线一区| 日本亚洲欧美色视频在线播放| 亚洲AV电影天堂男人的天堂| 国产精品成人亚洲| 一级黄色毛片免费看| a级毛片高清免费视频| 日本高清高色视频免费| 毛片免费全部播放无码| 欧美在线看片A免费观看| 成人免费视频软件网站| 超pen个人视频国产免费观看| 免费日韩在线视频| 亚洲精品无码不卡在线播HE| 4480yy私人影院亚洲| 亚洲乱码在线卡一卡二卡新区| 爱情岛论坛亚洲品质自拍视频网站| 成人a毛片视频免费看| 日本免费在线观看| 可以免费看黄的网站| 免费国产怡红院在线观看| 亚洲精品少妇30p| 亚洲精品456在线播放| 亚洲AV无码一区二区三区电影| 精品97国产免费人成视频| 久久狠狠躁免费观看2020|