🚀Spring Boot + ShardingSphere 實戰:分庫分表,性能暴增的終極指南!
? 適用場景:千萬級大表、高并發、讀寫分離場景
? 核心框架:Spring Boot 3.x + ShardingSphere-JDBC 5.4.1
? 數據庫:MySQL 8.x(主從結構)
? 特色亮點:覆蓋垂直/水平分庫、分表、自定義分片、公共表、廣播表、Hint 強制路由
分庫分表 vs 讀寫分離 vs 主從配置與數據庫高可用架構區別
📚 目錄
- 🌟 為什么選擇 ShardingSphere?
- 📐 系統整體架構圖
- 🧰 技術選型與版本說明
- ?? 核心配置詳解
- 🚦 常用查詢效果演示
- 🚧 常見問題與優化建議
- 📎 參考資料與源碼下載
🌟 為什么選擇 ShardingSphere?
ShardingSphere 是 Apache 開源的數據庫中間件生態系統,支持 JDBC 層嵌入和獨立代理部署,擁有強大的分庫分表、讀寫分離、數據加密、彈性擴容、分布式事務等能力。相比傳統中間件,它更靈活、社區更活躍,適合大多數 Spring Boot 應用快速集成。
🔍 什么是 ShardingSphere?
ShardingSphere 是一個開源的分布式數據庫中間件生態,最早由當當網開源(Sharding-JDBC),目前由 Apache 基金會孵化。
它包含 3 大組件:
組件 | 作用說明 |
---|---|
ShardingSphere-JDBC | 輕量級 Java JDBC 層分庫分表工具(無需 Proxy) |
ShardingSphere-Proxy | 基于 MySQL/PostgreSQL 協議的中間件代理層 |
ShardingSphere-Sidecar | 面向 Kubernetes 的數據庫 Mesh Sidecar |
本項目使用 ShardingSphere-JDBC,適合嵌入 Spring Boot 項目,無需額外服務。
🌟 ShardingSphere 的核心能力
能力項 | 說明 |
---|---|
? 分庫分表 | 支持標準、綁定表、廣播表、Hint 路由等 |
? 讀寫分離 | 支持一主多從,負載均衡策略可配置 |
? 彈性擴容 | 數據遷移過程中支持雙寫、多活等策略 |
? 分布式事務 | 支持 Seata/XA/BASE 模式 |
? 數據加密 | 支持字段級加密與脫敏 |
? 容器/K8s 支持 | Proxy 和 Sidecar 支持云原生部署 |
? SQL 顯示/日志跟蹤 | 方便調試分片路由結果 |
🧠 為什么選它而不是其他?
對比項 | ShardingSphere | MyCat | Vitess/Federation |
---|---|---|---|
📦 部署方式 | 代碼嵌入(JDBC層)或獨立服務 | 獨立服務(代理層) | 代理層(復雜度較高) |
💡 配置方式 | YAML/Java/Registry/動態 | XML 配置復雜 | 支持 SQL 路由 |
🧩 特性完整度 | 高:分片+讀寫+事務+加密 | 分片較強,其他較弱 | 分布式強,學習成本高 |
🌐 社區活躍度 | 高(Apache孵化+大廠支持) | 較低(更新慢) | 中(主要在國外) |
💼 實際落地場景 | 電商、支付、運營平臺等 | 早期用得多,現在轉向替代 | 海外云廠商多 |
🧪 分布式事務支持 | ? Seata / BASE / XA | ? | ? |
📌 結論:ShardingSphere 在 兼容性、靈活性、社區支持 等方面都具備絕對優勢,適合中大型項目長期維護。
🧪 哪種場景適合使用 ShardingSphere?
場景類型 | 是否推薦使用 | 說明 |
---|---|---|
訂單系統 | ? | 支持訂單分庫分表,按用戶、時間分片都很靈活 |
用戶系統 | ?(廣播表) | 用戶表一般較小,可廣播全庫保持一致 |
內容系統 | ? | 文章/評論按ID、日期分表效果好 |
實時大數據 | ?(不推薦) | 建議用 Flink + Hive/Spark |
跨庫強事務需求 | ?(結合 Seata) | ShardingSphere + Seata 實現分布式事務 |
多租戶 SaaS | ? | 可按 tenant_id 分庫分表 + 廣播共享配置類 |
📌 總結一句話:
ShardingSphere 是 Java 世界中最成熟、最活躍的分庫分表中間件,適合絕大多數業務場景,尤其適合 Spring Boot 用戶接入。
📐 系統整體架構圖
🧩 用戶模塊使用廣播表,訂單模塊按 user_id 水平分庫,order 表按年月分表,日志表歸檔存儲。讀寫分離策略基于 SQL 類型自動路由到主庫或從庫。
下面是一個標準的 ShardingSphere 架構圖,展示其核心組件、功能模塊和部署方式。架構可以分為三種模式:ShardingSphere-JDBC、ShardingSphere-Proxy、ShardingSphere-Sidecar(計劃中)。這里我們重點展示 ShardingSphere-JDBC 和 ShardingSphere-Proxy 的部署結構:
? 一、ShardingSphere 總體架構圖(邏輯圖)
? 二、ShardingSphere 三種部署模式對比圖
模式 | 架構位置 | 特點說明 |
---|---|---|
ShardingSphere-JDBC | Java 應用內部 | 嵌入式、輕量級,支持事務、本地運行、性能高。適合 Java 項目 |
ShardingSphere-Proxy | 數據庫代理層 | 類似 MySQL 中間件,跨語言支持(Python、Go等),統一訪問 |
ShardingSphere-Sidecar(未來) | Service Mesh(Istio)邊車模式 | 云原生、K8s友好,服務間透明代理 |
? 三、ShardingSphere-JDBC 架構圖
? 四、ShardingSphere-Proxy 架構圖
? 五、組件模塊圖(ShardingSphere 功能生態)
🧰 技術選型與版本說明
技術棧 | 說明 |
---|---|
Spring Boot | 3.1.5 |
ShardingSphere-JDBC | 5.2.1 |
MyBatis-Plus | 3.5.11 |
MySQL | 8.0.x,一主兩從 |
dynamic-datasource | 與 ShardingSphere 不兼容,已棄用 |
Lombok / HikariCP | 簡化開發 / 高性能連接池 |
?? 核心配置詳解(application.yml)
📌 一、項目整體結構預覽
sharding-demo/
├── src/
│ ├── main/
│ │ ├── java/com/example/shardingdemo/
│ │ │ ├── controller/
│ │ │ ├── entity/
│ │ │ ├── mapper/
│ │ │ ├── ShardingDemoApplication.java
│ └── resources/
│ ├── application.yml
├── pom.xml
🧱 二、核心依賴配置(pom.xml)
<dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version> <!-- 使用最新版本 --></dependency><!-- MyBatis Plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.11</version></dependency><!-- ShardingSphere-JDBC --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>5.2.1</version></dependency><!-- MySQL Connector --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><!-- Lombok & Fastjson 可選 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
🧬 三、數據結構設計(核心表)
1?? 用戶表(廣播表)
CREATE TABLE t_user (id BIGINT PRIMARY KEY,username VARCHAR(50),phone VARCHAR(20)
);
2?? 訂單主表(分庫 + 分表)
CREATE TABLE t_order_0 (id BIGINT PRIMARY KEY,user_id BIGINT,order_no VARCHAR(64),amount DECIMAL(10,2),create_time DATETIME
);
CREATE TABLE t_order_1 (id BIGINT PRIMARY KEY,user_id BIGINT,order_no VARCHAR(64),amount DECIMAL(10,2),create_time DATETIME
);
CREATE TABLE t_order_2 (id BIGINT PRIMARY KEY,user_id BIGINT,order_no VARCHAR(64),amount DECIMAL(10,2),create_time DATETIME
);
?? 四、application.yml 配置(核心)
spring:shardingsphere:datasource:names: ds0, ds1, ds2ds0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://mysql-master:3307/testdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: rootds1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://mysql-slave1:3308/testdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: rootds2:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://mysql-slave2:3309/testdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: rootrules:sharding:tables:t_order:actual-data-nodes: ds$->{0..2}.t_order_$->{0..2}table-strategy:standard:sharding-column: user_idsharding-algorithm-name: order-table-inline # 使用 sharding-algorithm-namedatabase-strategy:standard:sharding-column: user_idsharding-algorithm-name: order-db-inlinebroadcast-tables:- t_userdefault-database-strategy:none:default-table-strategy:none:sharding-algorithms:order-db-inline:type: INLINEprops:algorithm-expression: ds${user_id % 3}order-table-inline:type: INLINEprops:algorithm-expression: t_order_${user_id % 3}props:sql-show: true
ShardingSphere-JDBC 配置詳解
1. 數據源配置 (datasource
)
定義了 3 個 MySQL 數據源(ds0
、ds1
、ds2
),分別指向主庫和從庫。
配置項 | 說明 |
---|---|
spring.shardingsphere.datasource.names | 數據源名稱列表(ds0, ds1, ds2 ) |
ds0.type | 數據源類型(HikariCP 連接池) |
ds0.driver-class-name | JDBC 驅動類(MySQL 8.0+) |
ds0.jdbc-url | 主庫連接 URL(mysql-master:3307 ) |
ds0.username / ds0.password | 數據庫登錄憑據(root/root ) |
ds1.jdbc-url | 從庫 1 連接 URL(mysql-slave1:3308 ) |
ds2.jdbc-url | 從庫 2 連接 URL(mysql-slave2:3309 ) |
2. 分片規則 (rules.sharding
)
(1) 表分片配置 (tables
)
配置 t_order
表的分庫分表策略。
配置項 | 說明 |
---|---|
t_order.actual-data-nodes | 實際數據節點格式: - ds$->{0..2}.t_order_$->{0..2} 表示: - 數據源:ds0 、ds1 、ds2 - 表:t_order_0 、t_order_1 、t_order_2 |
t_order.table-strategy | 表分片策略(按 user_id 分片) |
t_order.database-strategy | 庫分片策略(按 user_id 分庫) |
(2) 分片算法 (sharding-algorithms
)
定義庫和表的分片算法。
算法名稱 | 類型 | 算法表達式 | 說明 |
---|---|---|---|
order-db-inline | INLINE | ds${user_id % 3} | 根據 user_id % 3 路由到 ds0 /ds1 /ds2 |
order-table-inline | INLINE | t_order_${user_id % 3} | 根據 user_id % 3 路由到 t_order_0 /t_order_1 /t_order_2 |
(3) 廣播表 (broadcast-tables
)
配置 t_user
表為廣播表(所有庫全量同步)。
配置項 | 說明 |
---|---|
broadcast-tables | 廣播表列表(t_user ) |
(4) 默認策略 (default-*
)
顯式禁用默認分庫分表策略(僅對未配置的表生效)。
配置項 | 說明 |
---|---|
default-database-strategy.none | 默認不分庫 |
default-table-strategy.none | 默認不分表 |
3. 屬性配置 (props
)
配置項 | 說明 |
---|---|
sql-show: true | 打印 SQL 日志(調試用) |
完整配置總結
層級 | 關鍵配置項 | 作用 |
---|---|---|
數據源 | datasource.names | 定義 3 個數據源(ds0 , ds1 , ds2 ) |
分片規則 | tables.t_order.actual-data-nodes | 邏輯表 t_order 映射到 3 個庫的 3 張分表(共 9 張表) |
分片策略 | database-strategy / table-strategy | 按 user_id 分庫分表 |
分片算法 | order-db-inline / order-table-inline | 通過取模運算路由數據 |
廣播表 | broadcast-tables: t_user | t_user 表在所有庫中全量同步 |
調試 | sql-show: true | 打印實際執行的 SQL |
潛在問題檢查
- 表名沖突
- 確保數據庫中不存在名為
order
的表(你的配置已使用t_order
,無沖突)。
- 確保數據庫中不存在名為
- 分表是否創建
- 需手動創建所有分表(如
ds0.t_order_0
,ds1.t_order_1
等)。
- 需手動創建所有分表(如
- 分片鍵類型
user_id
應為數值類型(否則%
運算可能失敗)。
- SQL 日志驗證
- 啟用
sql-show: true
后,觀察日志確認路由是否正確。
- 啟用
示例 SQL 路由結果
假設 user_id = 5
:
-
分庫路由:
5 % 3 = 2
→ds2
-
分表路由:
5 % 3 = 2
→t_order_2
-
最終 SQL:
INSERT INTO t_order_2 (id, user_id, ...) VALUES (?, 5, ...)
執行在 ds2 數據源上。
通過以上配置,ShardingSphere 會根據 user_id
自動將數據分散到不同的庫和表中。如果仍有問題,建議檢查:
- 數據庫表是否已創建。
- 分片鍵
user_id
的值是否符合預期。 - 日志中輸出的實際 SQL 是否符合分片邏輯。
🧩 五、Java 實體與 DAO 層設計
實體類
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.math.BigDecimal;
import java.time.LocalDateTime;@Data
@TableName("t_order")
public class Order {private Long id;private Long userId;private String orderNo;private BigDecimal amount;private LocalDateTime createTime;
}
Mapper接口
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.shardingdemo.entity.Order;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
Controller接口
import cn.hutool.core.util.IdUtil;
import com.example.shardingdemo.entity.Order;
import com.example.shardingdemo.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate OrderMapper orderMapper;@PostMapping("/create")public String createOrder() {Order order = new Order();order.setId(IdUtil.getSnowflakeNextId());order.setUserId(1001L);order.setOrderNo("ORDER_" + System.currentTimeMillis());order.setAmount(new BigDecimal("99.99"));order.setCreateTime(LocalDateTime.now());orderMapper.insert(order);return "OK";}@GetMapping("/list")public List<Order> listOrders() {return orderMapper.selectList(null);}
}
🚦 常用查詢效果演示
? 寫入數據
Logic SQL: INSERT INTO t_order ( id, user_id, order_no, amount, create_time ) VALUES ( ?, ?, ?, ?, ? )
Actual SQL: ds2 ::: INSERT INTO t_order_2 ( id, user_id, order_no, amount, create_time ) VALUES (?, ?, ?, ?, ?) ::: [1952250075647401984, 1001, ORDER_1754287663743, 99.99, 2025-08-04T14:07:43.743983]
計算 userId=1001 的路由結果
(1) 分庫計算
1001 % 3 = 2 // 余數為 2
目標庫:ds2(對應 ds${2})
(2) 分表計算
1001 % 3 = 2 // 余數仍為 2
目標表:t_order_2(對應 t_order_${2})
? 查詢數據
Actual SQL: ds2 ::: SELECT id,user_id,order_no,amount,create_time FROM t_order_0 WHERE id=? UNION ALL SELECT id,user_id,order_no,amount,create_time FROM t_order_1 WHERE id=? UNION ALL SELECT id,user_id,order_no,amount,create_time FROM t_order_2 WHERE id=? ::: [1952241523566383104, 1952241523566383104, 1952241523566383104]
👉 自動路由,跨表/跨庫查詢時支持 Merge 結果集
🚧 常見問題與優化建議
問題/瓶頸 | 原因分析 | 優化建議 |
---|---|---|
跨庫查詢慢 | 無法使用索引 | 避免跨庫;結合分片鍵做等值過濾 |
寫入熱點庫慢 | 分片策略不均勻 | 使用雪花 ID + hash 分庫分表策略 |
SQL 不支持 | 復雜 JOIN / 子查詢等 | 拆分邏輯到應用層,使用綁定表提升性能 |
分布式事務處理 | 多庫事務需要協調 | 引入 Seata 或采用 BASE 最終一致性方案 |
分片表擴容麻煩 | 表名寫死、規則不靈活 | 使用 Hint / 時間分片表達式 / Inline 表達式 |
📎 參考資料與源碼下載
- 🔗 官方文檔(ShardingSphere)
💬 如果你覺得這篇文章對你有幫助,歡迎點贊 + 收藏 + 評論,一起交流分庫分表最佳實踐!