# 如何使用分库分表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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。