【ShardingSphere】ShardingSphere-JDBC 快速入門


一、簡介

  官網:https://shardingsphere.apache.org/index_zh.html

  文檔:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/overview/

  ShardingSphere-JDBC 是 Apache ShardingSphere 的第一個產品,也是 Apache ShardingSphere 的前身。 定位為輕量級 Java 框架,在 Java 的 JDBC 層提供的額外服務。 它使用客戶端直連數據庫,以 jar 包形式提供服務,無需額外部署和依賴,可理解為增強版的 JDBC 驅動,完全兼容 JDBC 和各種 ORM 框架。

  • 適用於任何基於 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
  • 支持任何第三方的數據庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP 等。
  • 支持任意實現 JDBC 規范的數據庫,目前支持 MySQL,Oracle,SQLServer,PostgreSQL 以及任何遵循 SQL92 標准的數據庫。

  

二、對比

  ShardingSphere-JDBC ShardingSphere-Proxy ShardingSphere-Sidecar
數據庫 任意 MySQL/PostgreSQL MySQL/PostgreSQL
連接消耗數
異構語言 僅Java 任意 任意
性能 損耗低 損耗略高 損耗低
無中心化
靜態入口

  ShardingSphere-JDBC 的優勢在於對 Java 應用的友好度。

三、核心概念

邏輯表

  水平拆分的數據庫(表)的相同邏輯和數據結構表的總稱。例:訂單數據根據主鍵尾數拆分為 10 張表,分別是 t_order_0 到 t_order_9,他們的邏輯表名為 t_order

真實表

  在分片的數據庫中真實存在的物理表。即上個示例中的 t_order_0 到 t_order_9

數據節點

  數據分片的最小單元。由數據源名稱和數據表組成,例:ds_0.t_order_0

綁定表

  指分片規則一致的主表和子表。例如:t_order 表和 t_order_item 表,均按照 order_id 分片,則此兩張表互為綁定表關系。綁定表之間的多表關聯查詢不會出現笛卡爾積關聯,關聯查詢效率將大大提升。舉例說明,如果 SQL 為:

SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); 

  在不配置綁定表關系時,假設分片鍵 order_id 將數值 10 路由至第 0 片,將數值 11 路由至第 1 片,那么路由后的 SQL 應該為 4 條,它們呈現為笛卡爾積:

SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); 

  在配置綁定表關系后,路由的 SQL 應該為 2 條:

SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); 

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

廣播表

  指所有的分片數據源中都存在的表,表結構和表中的數據在每個數據庫中均完全一致。適用於數據量不大且需要與海量數據的表進行關聯查詢的場景,例如:字典表。

單表

  指所有的分片數據源中只存在唯一一張的表。適用於數據量不大且不需要做任何分片操作的場景。

分片鍵

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

分片算法

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

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

  • 標准分片算法

  對應 StandardShardingAlgorithm,用於處理使用單一鍵作為分片鍵的 =INBETWEEN AND><>=<= 進行分片的場景。需要配合 StandardShardingStrategy 使用。

  • 復合分片算法

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

  • Hint分片算法

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

分片策略

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

  • 標准分片策略

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

  • 復合分片策略

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

  • Hint分片策略

  對應 HintShardingStrategy。通過 Hint 指定分片值而非從 SQL 中提取分片值的方式進行分片的策略。

  • 不分片策略

  對應 NoneShardingStrategy。不分片的策略。

SQL Hint

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

四、數據分片使用

  1、在mysql中,新建2個數據庫 test-shardingsphere1 與 test-shardingsphere2

1 CREATE TABLE IF NOT EXISTS t_order_0 (order_id INT NOT NULL, user_id INT NOT NULL, status VARCHAR(45) NULL, PRIMARY KEY (order_id));
2 CREATE TABLE IF NOT EXISTS t_order_1 (order_id INT NOT NULL, user_id INT NOT NULL, status VARCHAR(45) NULL, PRIMARY KEY (order_id));
3 CREATE TABLE IF NOT EXISTS t_order_item_0 (item_id INT NOT NULL, order_id INT NOT NULL, user_id INT NOT NULL, status VARCHAR(45) NULL, PRIMARY KEY (item_id));
4 CREATE TABLE IF NOT EXISTS t_order_item_1 (item_id INT NOT NULL, order_id INT NOT NULL, user_id INT NOT NULL, status VARCHAR(45) NULL, PRIMARY KEY (item_id));
 1 INSERT INTO t_order VALUES(1000, 10, 'init');
 2 INSERT INTO t_order VALUES(1001, 10, 'init');
 3 INSERT INTO t_order VALUES(1100, 11, 'init');
 4 INSERT INTO t_order VALUES(1101, 11, 'init');
 5 INSERT INTO t_order_item VALUES(100000, 1000, 10, 'init');
 6 INSERT INTO t_order_item VALUES(100001, 1000, 10, 'init');
 7 INSERT INTO t_order_item VALUES(100100, 1001, 10, 'init');
 8 INSERT INTO t_order_item VALUES(100101, 1001, 10, 'init');
 9 INSERT INTO t_order_item VALUES(110000, 1100, 11, 'init');
10 INSERT INTO t_order_item VALUES(110001, 1100, 11, 'init');
11 INSERT INTO t_order_item VALUES(110100, 1101, 11, 'init');
12 INSERT INTO t_order_item VALUES(110101, 1101, 11, 'init');

  2、新建maven項目,引入依賴

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>com.test.sharding</groupId>
 8     <artifactId>test-sharding-jdbc</artifactId>
 9     <version>1.0-SNAPSHOT</version>
10 
11     <properties>
12         <maven.compiler.source>8</maven.compiler.source>
13         <maven.compiler.target>8</maven.compiler.target>
14     </properties>
15 
16     <dependencies>
17         <!-- shardingsphere-jdbc -->
18         <dependency>
19             <groupId>org.apache.shardingsphere</groupId>
20             <artifactId>shardingsphere-jdbc-core</artifactId>
21             <version>5.0.0-beta</version>
22         </dependency>
23 
24         <!-- mysql -->
25         <dependency>
26             <groupId>mysql</groupId>
27             <artifactId>mysql-connector-java</artifactId>
28             <version>8.0.12</version>
29         </dependency>
30 
31 
32         <!-- 日志 -->
33         <dependency>
34             <groupId>org.slf4j</groupId>
35             <artifactId>slf4j-simple</artifactId>
36             <version>1.7.25</version>
37             <scope>compile</scope>
38         </dependency>
39     </dependencies>
40 
41 </project>

  3、Java代碼如下:

  1 /**
  2  * 水平分庫分表
  3  */
  4 public class ShardingJDBCTest {
  5 
  6     public static void main(String[] args) throws SQLException {
  7 //        ShardingJDBCTest.insert();
  8         ShardingJDBCTest.select();
  9     }
 10 
 11 
 12 
 13     public static void insert() throws SQLException {
 14         // 獲取數據源
 15         DataSource dataSource = getDataSource();
 16 
 17         String insertSql1 = "INSERT INTO t_order VALUES(1000, 10, 'init');";
 18         String insertSql2 = "INSERT INTO t_order VALUES(1001, 10, 'init');";
 19         String insertSql3 = "INSERT INTO t_order VALUES(1100, 11, 'init');";
 20         String insertSql4 = "INSERT INTO t_order VALUES(1101, 11, 'init');";
 21 
 22         try (
 23                 Connection conn = dataSource.getConnection();
 24                 PreparedStatement ps = conn.prepareStatement(insertSql3)) {
 25             int num = ps.executeUpdate();
 26             System.out.println("num = " + num);
 27         }
 28 
 29     }
 30 
 31     public static void select() throws SQLException {
 32         // 獲取數據源
 33         DataSource dataSource = getDataSource();
 34 
 35 //        String sql = "select * from t_order order";
 36         String sql = "select * from t_order order by user_id desc";
 37 //        String sql = "select * from t_order order by order_id desc limit 2";
 38 
 39         try (
 40                 Connection conn = dataSource.getConnection();
 41                 PreparedStatement ps = conn.prepareStatement(sql)) {
 42             try (ResultSet rs = ps.executeQuery()) {
 43                 while(rs.next()) {
 44                     int order_id = rs.getInt(1);
 45                     int user_id = rs.getInt(2);
 46                     String status = rs.getString(3);
 47                     System.out.println(order_id + "\t" + user_id + "\t" + status);
 48                 }
 49             }
 50         }
 51     }
 52 
 53     public static DataSource getDataSource() throws SQLException {
 54         // 配置真實數據源
 55         Map<String, DataSource> dataSourceMap = new HashMap<>();
 56 
 57         // 配置第 1 個數據源
 58         HikariDataSource dataSource1 = new HikariDataSource();
 59         dataSource1.setDriverClassName("com.mysql.cj.jdbc.Driver");
 60         dataSource1.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test-shardingjdbc1?allowPublicKeyRetrieval=true&useSSL=true");
 61         dataSource1.setUsername("root");
 62         dataSource1.setPassword("123456");
 63         dataSourceMap.put("ds0", dataSource1);
 64 
 65         // 配置第 2 個數據源
 66         HikariDataSource dataSource2 = new HikariDataSource();
 67         dataSource2.setDriverClassName("com.mysql.cj.jdbc.Driver");
 68         dataSource2.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test-shardingjdbc2?allowPublicKeyRetrieval=true&useSSL=true");
 69         dataSource2.setUsername("root");
 70         dataSource2.setPassword("123456");
 71         dataSourceMap.put("ds1", dataSource2);
 72 
 73         // 配置 t_order 表規則
 74         ShardingTableRuleConfiguration orderTableRuleConfig = new ShardingTableRuleConfiguration("t_order", "ds${0..1}.t_order_${0..1}");
 75 
 76         // 配置分庫策略
 77         orderTableRuleConfig.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("user_id", "dbShardingAlgorithm"));
 78 
 79         // 配置分表策略
 80         orderTableRuleConfig.setTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm"));
 81 
 82         // 省略配置 t_order_item 表規則...
 83         // ...
 84 //        ShardingTableRuleConfiguration itemTableRuleConfig = new ShardingTableRuleConfiguration("t_order_item", "ds${0..1}.t_order_item_${0..1}");
 85 //        itemTableRuleConfig.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("user_id", "dbShardingAlgorithm"));
 86 //        itemTableRuleConfig.setTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm"));
 87 
 88 
 89         // 配置分片規則
 90         ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
 91         shardingRuleConfig.getTables().add(orderTableRuleConfig);
 92 
 93         // 配置分庫算法
 94         Properties dbShardingAlgorithmrProps = new Properties();
 95         dbShardingAlgorithmrProps.setProperty("algorithm-expression", "ds${user_id % 2}");
 96         shardingRuleConfig.getShardingAlgorithms().put("dbShardingAlgorithm",
 97                 new ShardingSphereAlgorithmConfiguration("INLINE", dbShardingAlgorithmrProps));
 98 
 99         // 配置分表算法
100         Properties tableShardingAlgorithmrProps = new Properties();
101         tableShardingAlgorithmrProps.setProperty("algorithm-expression", "t_order${order_id % 2}");
102         shardingRuleConfig.getShardingAlgorithms().put("tableShardingAlgorithm",
103                 new ShardingSphereAlgorithmConfiguration("INLINE", tableShardingAlgorithmrProps));
104 
105         // 創建 ShardingSphereDataSource
106         DataSource dataSource = ShardingSphereDataSourceFactory.createDataSource(dataSourceMap, Collections.singleton(shardingRuleConfig), new Properties());
107 
108         return dataSource;
109     }
110 }

 

   更多使用,請參考官網文檔


免責聲明!

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



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