分库分表之实战-sharding-JDBC水平分库+水平分表配置实战
大家好,我是工藤学编程 🦉 | 一个正在努力学习的小博主,期待你的关注 |
---|---|
实战代码系列最新文章😉 | C++实现图书管理系统(Qt C++ GUI界面版) |
SpringBoot实战系列🐷 | 【SpringBoot实战系列】Sharding-Jdbc实现分库分表到分布式ID生成器Snowflake自定义wrokId实战 |
环境搭建大集合 | 环境搭建大集合(持续更新) |
分库分表 | 分库分表之实战-sharding-JDBC广播表 |
前情摘要:
1、数据库性能优化
2、分库分表之优缺点分析
3、分库分表之数据库分片分类
4、分库分表之策略
5、分库分表技术栈讲解-Sharding-JDBC
6、分库分表下的 ID 冲突问题与雪花算法讲解
7、分库分表之实战-sharding-JDBC
8、分库分表之实战-sharding-JDBC广播表
【亲测宝藏】发现一个让 AI 学习秒变轻松的神站!不用啃高数、不用怕编程,高中生都能看懂的人工智能教程来啦!
👉点击跳转,和 thousands of 小伙伴一起用快乐学习法征服 AI,说不定下一个开发出爆款 AI 程序的就是你!
本文章目录
- Sharding-JDBC水平分库分表实战
- 一、分库分表架构设计与场景分析
- 二、库表数据清除与配置修改
- 三、执行结果与分片验证
- 四、进阶优化与注意事项
- 五、总结:水平分库分表的核心价值
Sharding-JDBC水平分库分表实战
一、分库分表架构设计与场景分析
前言:
项目工程紧接:分库分表之实战-sharding-JDBC广播表。
核心分片策略
- 分库规则:按
user_id
取模分片(user_id % 2
),确保同一用户的订单集中在同一库 - 分表规则:按
product_order_id
(订单号)取模分片(product_order_id % 2
),分散单库内的数据压力
二、库表数据清除与配置修改
首先我们将之前章节产生的数据清除,避免印象本章节的测试
然后application.properties中新增内容,将之前分表规则由user_id改为订单自身的id,并且需要将真实节点改为库+表
#配置分库规则
spring.shardingsphere.sharding.tables.product_order.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.database-strategy.inline.algorithm-expression=ds$->{user_id % 2}#将之前分表规则由user_id改为订单自身的id
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{id % 2}#原本为ds0.product_order_$->{0..1}
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}
在DbTest中新增单元测试函数
@Testpublic void testSaveProductOrderDB(){Random random = new Random();for(int i=0;i<20;i++){ProductOrderDO productOrder = new ProductOrderDO();productOrder.setCreateTime(new Date());productOrder.setNickname("ccc_i="+i);productOrder.setOutTradeNo(UUID.randomUUID().toString().substring(0,32));productOrder.setPayAmount(100.00);productOrder.setState("PAY");productOrder.setUserId(Math.abs(random.nextLong()));productOrderMapper.insert(productOrder);}}
三、执行结果与分片验证
1. SQL执行日志(关键输出)
- 逻辑 SQL(统一的抽象 SQL):
逻辑 SQL 是开发者编写的、针对逻辑表的 SQL 语句,不关心数据实际存储在哪个物理库或物理表,是对分库分表逻辑的抽象。
INSERT INTO product_order (id, out_trade_no, state, create_time, pay_amount, nickname, user_id) VALUES (?, ?, ?, ?, ?, ?, ?)
- 特点
面向逻辑表:product_order是逻辑表(代表整个分库分表的数据集,而非具体某一张物理表)。
与分库分表无关:开发者无需关心数据最终存在ds0还是ds1,也无需关心存在product_order_0还是product_order_1。
参数化:使用?作为占位符,参数由业务代码传入(如id、user_id等)。
统一抽象:无论数据分布在多少个库表,逻辑 SQL 的写法保持一致,简化开发。 - 实际 SQL(路由到具体库表):
实际 SQL 是 Sharding-JDBC 根据分库分表策略,将逻辑 SQL 转换为针对具体物理库和物理表的可执行 SQL 语句。
#路由到ds1.product_order_0:
INSERT INTO product_order_0 (...) VALUES (...) ::: [1942559776326320130, 70bd5220-1c9c-4e3e-b418-85481f60, PAY, 2025-07-08 20:21:56.32, 100.0, ccc_i=0, 204402002533403893]
#路由到ds0.product_order_1
INSERT INTO product_order_1 (...) VALUES (...) ::: [1942559778821931009, 3fe7e14a-e75b-4c44-905e-7cc4efb3, PAY, 2025-07-08 20:21:56.952, 100.0, ccc_i=1, 164530429416077594]
- 特点
面向物理库表:
ds1/ds0是具体的物理库(对应配置中的数据源)。
product_order_0/product_order_1是具体的物理表(逻辑表product_order拆分后的实际表)。
由分库分表策略决定:
分库:根据user_id % 2计算(如user_id=204402002533403893时,204402002533403893 % 2 = 1 → 路由到ds1)。
**分表:**根据id % 2计算(如id=1942559776326320130时,1942559776326320130 % 2 = 0 → 路由到product_order_0)。
**包含实际参数:**占位符?被具体值替换(如主键id、user_id等)。
可直接执行:是数据库能直接识别并执行的 SQL。
2. 数据库验证(分片结果) - ds_0库:
order_0
表:存储user_id偶数、order_id偶数的订单
order_1
表:存储user_id偶数、order_id奇数的订单
- ds_1库:
order_0
表:存储user_id奇数、order_id偶数的订单
order_1
表:存储user_id奇数、order_id奇数的订单
四、进阶优化与注意事项
1. 分片键选择建议
- 避免热点问题:若
user_id
分布不均(如某些用户订单量极大),可考虑复合分片(如user_id + 时间
) - 查询场景优先:分片键需覆盖高频查询条件(如按
user_id
查询订单时,分片键选择user_id
可避免跨库查询)
2. 跨库查询解决方案
- 广播表关联:若订单需关联商品表,可将商品表设为广播表(参考Sharding-JDBC广播表实战)
- 分库查询后聚合:复杂跨库查询可通过
ShardingSphere
的StreamResultSet
接口实现结果聚合
3. 分布式事务处理
Sharding-JDBC原生支持BASE事务(通过XA
或柔性事务
),若订单涉及跨库更新(如扣库存),需结合Seata
等分布式事务框架。
五、总结:水平分库分表的核心价值
通过本案例实现的2库4表架构,可带来以下收益:
- 性能提升:单表数据量降低,索引查询效率提升30%+
- 负载均衡:数据分散到多个数据库,CPU/IO资源利用率更均衡
适用场景:订单系统、交易记录、用户日志等数据量大且写入频繁的业务场景。
觉得有用请点赞收藏!
如果有相关问题,欢迎评论区留言讨论~