# 如何使用分庫分表Sharding-JDBC
## 目錄
- [一、分庫分表核心概念](#一分庫分表核心概念)
- [1.1 什么是分庫分表](#11-什么是分庫分表)
- [1.2 垂直拆分與水平拆分](#12-垂直拆分與水平拆分)
- [1.3 分庫分表適用場景](#13-分庫分表適用場景)
- [二、Sharding-JDBC架構解析](#二sharding-jdbc架構解析)
- [2.1 核心組件與工作原理](#21-核心組件與工作原理)
- [2.2 與MyCat對比](#22-與mycat對比)
- [2.3 版本演進與新特性](#23-版本演進與新特性)
- [三、基礎環境搭建](#三基礎環境搭建)
- [3.1 依賴配置](#31-依賴配置)
- [3.2 數據源配置](#32-數據源配置)
- [3.3 分片規則配置](#33-分片規則配置)
- [四、分片策略詳解](#四分片策略詳解)
- [4.1 標準分片策略](#41-標準分片策略)
- [4.2 復合分片策略](#42-復合分片策略)
- [4.3 Hint分片策略](#43-hint分片策略)
- [4.4 不分片策略](#44-不分片策略)
- [五、分布式事務實現](#五分布式事務實現)
- [5.1 XA事務](#51-xa事務)
- [5.2 Seata柔性事務](#52-seata柔性事務)
- [5.3 BASE事務](#53-base事務)
- [六、實戰案例](#六實戰案例)
- [6.1 電商訂單分庫分表](#61-電商訂單分庫分表)
- [6.2 多租戶SAAS系統](#62-多租戶saas系統)
- [6.3 物聯網時序數據](#63-物聯網時序數據)
- [七、性能優化](#七性能優化)
- [7.1 路由優化](#71-路由優化)
- [7.2 合并執行優化](#72-合并執行優化)
- [7.3 連接池配置](#73-連接池配置)
- [八、運維監控](#八運維監控)
- [8.1 指標監控集成](#81-指標監控集成)
- [8.2 鏈路追蹤](#82-鏈路追蹤)
- [8.3 慢查詢分析](#83-慢查詢分析)
- [九、常見問題解決方案](#九常見問題解決方案)
- [9.1 分布式ID生成](#91-分布式id生成)
- [9.2 跨庫JOIN處理](#92-跨庫join處理)
- [9.3 分布式序列問題](#93-分布式序列問題)
- [十、未來發展趨勢](#十未來發展趨勢)
- [10.1 云原生支持](#101-云原生支持)
- [10.2 多模異構支持](#102-多模異構支持)
- [10.3 智能化方向](#103-智能化方向)
## 一、分庫分表核心概念
### 1.1 什么是分庫分表
分庫分表是數據庫水平擴展的核心技術手段,主要解決單機數據庫在數據量增長時出現的性能瓶頸問題。當單表數據量超過500萬行或數據庫實例QPS超過3000時,就應該考慮分庫分表方案。
**技術本質**:通過數據分片(Sharding)將數據集分散到不同的物理節點,使每個節點只處理部分數據,從而提升整體系統的處理能力。
### 1.2 垂直拆分與水平拆分
#### 垂直拆分(Vertical Partitioning)
```sql
-- 原始用戶表
CREATE TABLE user (
id BIGINT,
username VARCHAR(50),
password VARCHAR(100),
profile_json TEXT,
login_log TEXT
);
-- 拆分后
CREATE TABLE user_basic (
id BIGINT,
username VARCHAR(50),
password VARCHAR(100)
);
CREATE TABLE user_profile (
user_id BIGINT,
profile_json TEXT
);
// 按用戶ID范圍分片
shardingRuleConfig.getTableRuleConfigs().add(
TableRuleConfiguration.builder("t_order")
.actualDataNodes("ds${0..1}.t_order_${0..15}")
.databaseShardingStrategy(
new StandardShardingStrategyConfiguration("user_id", "dbShardingAlgorithm"))
.tableShardingStrategy(
new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm"))
.build());
場景類型 | 典型特征 | 解決方案 |
---|---|---|
高并發讀寫 | QPS > 5000 | 分庫分散壓力 |
大數據量存儲 | 單表 > 500萬行 | 分表存儲 |
地理分布式訪問 | 跨地域訪問延遲高 | 按地域分庫 |
多租戶系統 | 租戶數據隔離需求 | 按租戶ID分庫 |
graph TD
A[應用代碼] --> B[Sharding-JDBC Driver]
B --> C[SQL解析引擎]
C --> D[路由引擎]
D --> E[改寫引擎]
E --> F[執行引擎]
F --> G[結果歸并]
G --> H[返回結果]
關鍵組件說明: 1. SQL解析:基于Apache Calcite實現SQL語法樹解析 2. 路由引擎:支持精確路由、范圍路由、廣播路由等多種模式 3. 執行引擎:自動建立多線程執行管道 4. 歸并引擎:支持流式歸并、內存歸并等多種方式
特性 | Sharding-JDBC | MyCat |
---|---|---|
架構模式 | 客戶端直連 | 代理層 |
性能損耗 | % | 15%-20% |
功能完整性 | 分片+分布式事務 | 分片+集群管理 |
運維復雜度 | 低(無中間件) | 高(需維護代理) |
版本迭代 | 活躍(Apache維護) | 社區維護 |
5.x版本重大改進: 1. 可插拔架構:支持SPI擴展 2. 分布式事務:XA/SAGA/SEATA全支持 3. 數據加密:列級別透明加密 4. 影子庫壓測:全鏈路壓測支持
Maven核心依賴:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
Spring Boot自動配置:
spring.shardingsphere.datasource.names=ds0,ds1
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/ds0
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
YAML格式配置示例:
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/ds0
username: root
password: 123456
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
maximum-pool-size: 20
Java API配置方式:
// 分片算法配置
Properties dbShardingProps = new Properties();
dbShardingProps.setProperty("algorithm-expression", "ds${user_id % 2}");
ShardingSphereAlgorithmConfiguration dbShardingAlgorithm =
new ShardingSphereAlgorithmConfiguration("INLINE", dbShardingProps);
// 表規則配置
ShardingTableRuleConfiguration orderTableRule = new ShardingTableRuleConfiguration(
"t_order", "ds${0..1}.t_order_${0..15}");
orderTableRule.setDatabaseShardingStrategy(
new StandardShardingStrategyConfiguration("user_id", "dbShardingAlgorithm"));
orderTableRule.setTableShardingStrategy(
new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm"));
精確分片算法實現:
public class OrderDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames,
PreciseShardingValue<Long> shardingValue) {
for (String each : availableTargetNames) {
if (each.endsWith(shardingValue.getValue() % 2 + "")) {
return each;
}
}
throw new IllegalArgumentException();
}
}
范圍分片算法示例:
public class OrderRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames,
RangeShardingValue<Long> shardingValue) {
Set<String> result = new LinkedHashSet<>();
Long lower = shardingValue.getValueRange().lowerEndpoint();
Long upper = shardingValue.getValueRange().upperEndpoint();
for (long i = lower; i <= upper; i++) {
for (String each : availableTargetNames) {
if (each.endsWith(i % 2 + "")) {
result.add(each);
}
}
}
return result;
}
}
多字段分片配置:
spring:
shardingsphere:
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..15}
database-strategy:
complex:
sharding-columns: user_id,order_date
algorithm-class-name: com.example.ComplexShardingAlgorithm
復合算法實現:
public class ComplexShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames,
ComplexKeysShardingValue<Comparable<?>> shardingValue) {
Map<String, Collection<Comparable<?>>> columnValues = shardingValue.getColumnNameAndShardingValuesMap();
Collection<Comparable<?>> userIds = columnValues.get("user_id");
Collection<Comparable<?>> orderDates = columnValues.get("order_date");
Set<String> result = new HashSet<>();
// 實現自定義復合分片邏輯
for (Comparable<?> userId : userIds) {
for (Comparable<?> orderDate : orderDates) {
int dbSuffix = (userId.hashCode() & Integer.MAX_VALUE) % 2;
int tableSuffix = orderDate.hashCode() % 16;
result.add(String.format("ds%d.t_order_%d", dbSuffix, tableSuffix));
}
}
return result;
}
}
強制路由配置:
// 設置分片值
HintManager.getInstance().setDatabaseShardingValue(1);
try {
// 執行SQL(將強制路由到ds1)
orderRepository.selectAll();
} finally {
HintManager.clear();
}
Hint算法實現:
public class OrderHintShardingAlgorithm implements HintShardingAlgorithm<Integer> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames,
HintShardingValue<Integer> shardingValue) {
Collection<String> result = new ArrayList<>();
for (String each : availableTargetNames) {
for (Integer value : shardingValue.getValues()) {
if (each.endsWith(value.toString())) {
result.add(each);
}
}
}
return result;
}
}
廣播表配置:
spring:
shardingsphere:
sharding:
broadcast-tables: t_config
綁定表配置:
spring:
shardingsphere:
sharding:
binding-tables:
- t_order,t_order_item
配置XA事務管理器:
spring:
shardingsphere:
props:
xa-transaction-manager-type: Atomikos
事務使用示例:
@ShardingSphereTransactionType(TransactionType.XA)
@Transactional
public void placeOrder(Order order) {
// 業務邏輯
}
Seata集成配置:
spring:
shardingsphere:
props:
seata:
tx-service-group: my_test_tx_group
AT模式示例:
@ShardingSphereTransactionType(TransactionType.BASE)
@Transactional
public void updateOrder(Order order) {
// 第一階段:執行業務SQL并生成undo log
orderMapper.update(order);
// 第二階段:由Seata自動提交/回滾
}
Saga模式配置:
@ShardingSphereTransactionType(TransactionType.SAGA)
@SagaStart(timeoutSeconds = 300)
public void createOrder(Order order) {
// 正向操作
orderService.create(order);
inventoryService.reduce(order.getItemId(), order.getCount());
// 補償操作定義
@Compensate
public void compensateCreate(Order order) {
orderService.delete(order.getId());
inventoryService.increase(order.getItemId(), order.getCount());
}
}
場景特點: - 訂單量日均10萬+ - 需要按用戶維度查詢 - 歷史訂單需要歸檔
分片方案:
spring:
shardingsphere:
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..3}.t_order_$->{0..15}
database-strategy:
inline:
sharding-column: user_id
algorithm-expression: ds$->{user_id % 4}
table-strategy:
standard:
sharding-column: order_time
precise-algorithm-class-name: com.example.OrderTimePreciseShardingAlgorithm
range-algorithm-class-name: com.example.OrderTimeRangeShardingAlgorithm
場景特點: - 租戶數量超過1000+ - 需要嚴格數據隔離 - 支持自定義租戶分片策略
解決方案:
public class TenantShardingAlgorithm implements PreciseShardingAlgorithm<String> {
@Override
public String doSharding(Collection<String> availableTargetNames,
PreciseShardingValue<String> shardingValue) {
// 根據租戶ID哈希分片
int hash = Math.abs(shardingValue.getValue().hashCode());
int index = hash % availableTargetNames.size();
return new ArrayList<>(availableTargetNames).get(index);
}
}
特殊需求: - 時間序列數據 - 需要定期自動創建新表 - 支持冷熱數據分離
動態分片方案:
public class TimeSeriesShardingAlgorithm implements PreciseShardingAlgorithm<Date> {
private static final DateTimeFormatter TABLE_FORMAT =
DateTimeFormatter.ofPattern("yyyy_MM");
@Override
public String doSharding(Collection<String> availableTargetNames,
PreciseShardingValue<Date> shardingValue) {
LocalDate date = shardingValue.getValue().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
String tableSuffix = date.format(TABLE_FORMAT);
return availableTargetNames.stream()
.filter(each -> each.endsWith(tableSuffix))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No table for date " + date));
}
}
最佳實踐: 1. 避免全庫全表掃描:
-- 錯誤寫法(導致廣播路由)
SELECT * FROM t_order WHERE status = 1;
-- 正確寫法(帶上分片鍵)
SELECT * FROM t_order WHERE user_id = 123 AND status = 1;
-- 分片鍵必須包含在索引中
ALTER TABLE t_order ADD INDEX idx_user_status (user_id, status);
配置參數調優:
spring:
shardingsphere:
props:
max.connections.size.per.query: 5 # 每個查詢最大連接數
executor.size: 20 # 執行線程池大小
kernel.executor.size: 20 # 內核線程池大小
HikariCP優化建議: “`yaml spring: shardingsphere: datasource: ds0: hikari: maximum-pool-size:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。