SpringBoot3+ShardingSphere分库分表实战与优化

发布时间:2026/7/4 1:55:09
SpringBoot3+ShardingSphere分库分表实战与优化 1. 项目概述作为一名经历过多次数据库性能瓶颈的后端开发者我深知单表数据量暴增带来的痛苦。最近在重构一个电商系统时订单表数据量已经突破3000万条查询响应时间从最初的200ms飙升到3秒以上严重影响了用户体验。经过多方评估最终选择了SpringBoot3 ShardingSphere-JDBC的方案来解决这个问题。这个方案最大的优势在于它对业务代码的零侵入性。我们不需要重写现有的DAO层和Service层代码只需要通过配置就能实现数据的水平拆分。在实际项目中我们仅用2天就完成了从单表到分库分表的平滑迁移查询性能提升了8倍写入延迟降低了90%。2. 环境准备与版本选型2.1 核心组件版本在技术选型时版本兼容性是最容易踩坑的地方。经过多次测试验证最终确定了以下稳定组合SpringBoot 3.2.5选择最新的稳定版充分利用其性能优化ShardingSphere-JDBC 5.5.2与SpringBoot3完美兼容的版本MySQL 8.0.31支持JSON类型和窗口函数等高级特性MyBatis-Plus 3.5.15简化CRUD操作JDK 17长期支持版本性能优于JDK11特别注意ShardingSphere 5.x版本对SpringBoot3的支持是从5.3.0开始的早期版本会出现自动配置失败的问题。我们团队曾尝试使用5.2.0版本结果遇到了Bean初始化异常。2.2 数据库设计我们采用经典的2库×2表分片方案数据库order_db_0、order_db_1表每个库包含t_order_0、t_order_1两张物理表建表时有个关键细节所有分表必须保持完全一致的结构。我们遇到过因为一个分表少了个索引导致查询性能差异巨大的情况。建议使用LIKE语法复制表结构CREATE TABLE t_order_1 LIKE t_order_0;3. 项目配置详解3.1 Maven依赖配置SpringBoot3的依赖管理与之前版本有所不同特别是MyBatis-Plus需要特殊处理dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-spring-boot3-starter/artifactId version3.5.15/version /dependency其他关键依赖包括shardingsphere-jdbc核心分库分表功能mysql-connector-jMySQL官方驱动hutool-all工具包用于生成分布式ID3.2 分片规则配置ShardingSphere 5.x推荐使用YAML分离式配置。我们在实践中发现这种方式的优势配置结构更清晰避免YAML缩进问题方便多环境切换application.yml关键配置spring: datasource: driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver url: jdbc:shardingsphere:classpath:sharding-datasource.yamlsharding-datasource.yaml核心配置解析rules: - !SHARDING tables: t_order: actualDataNodes: ds_${0..1}.t_order_${0..1} databaseStrategy: standard: shardingColumn: user_id shardingAlgorithmName: db-inline tableStrategy: standard: shardingColumn: user_id shardingAlgorithmName: tbl-inline shardingAlgorithms: db-inline: type: INLINE props: algorithm-expression: ds_${user_id % 2} tbl-inline: type: INLINE props: algorithm-expression: t_order_${user_id % 2}经验分享我们曾因为把algorithm-expression错写成algorithmExpression导致配置不生效调试了2小时才发现这个问题。ShardingSphere对配置项的命名非常严格。4. 业务代码实现4.1 实体类设计使用MyBatis-Plus注解简化代码Data TableName(t_order) // 关键指定逻辑表名 public class Order { TableId(type IdType.ASSIGN_ID) // 分布式ID private Long id; private String orderNo; private Long userId; // 分片键 // 其他字段... }4.2 Mapper与Service保持与单表操作完全一致的写法public interface OrderMapper extends BaseMapperOrder {} Service public class OrderService extends ServiceImplOrderMapper, Order {}4.3 控制器示例提供测试接口验证分片效果GetMapping(/add) public String addOrder(RequestParam Long userId) { Order order new Order(); order.setUserId(userId); // 必须设置分片键 // 其他字段设置... orderService.save(order); return success; }5. 测试与验证5.1 分片路由验证通过以下测试用例验证分片是否正确user_id1001 → 应路由到ds1.t_order_1user_id1002 → 应路由到ds0.t_order_0开启SQL日志后可以在控制台看到实际执行的SQLLogic SQL: INSERT INTO t_order... Actual SQL: ds1 ::: INSERT INTO t_order_1...5.2 性能对比测试我们使用JMeter进行了压测对比单表模式1000TPS时平均响应时间320ms分片模式1000TPS时平均响应时间45ms6. 深度优化与问题排查6.1 分布式ID生成避免使用数据库自增ID推荐方案雪花算法SnowflakeUUID适合小规模应用美团Leaf等专业方案我们最终选择了Hutool的雪花算法实现Bean public IdGenerator idGenerator() { return new DefaultIdGenerator(); }6.2 跨库查询优化分库后面临的新问题分页查询需要先在各分片查询后再内存合并排序操作同样需要内存处理聚合函数需要特殊处理解决方案// 使用ShardingSphere的HintManager强制路由 try (HintManager hintManager HintManager.getInstance()) { hintManager.addDatabaseShardingValue(t_order, 0); hintManager.addTableShardingValue(t_order, 0); // 执行查询... }6.3 常见错误排查分片键缺失执行SQL时必须包含分片键字段事务问题跨库事务需要使用XA或Seata等分布式事务方案连接池配置建议为每个分片单独配置连接池参数7. 生产环境建议经过多个项目的实践总结出以下经验监控配置集成Prometheus监控分片性能# application.yml metrics: enabled: true export: prometheus: enabled: true灰度发布先对读操作分片再处理写操作数据迁移使用ShardingSphere-Scaling进行在线迁移容量规划每个分片建议控制在500万条数据以内8. 扩展思考当数据量进一步增长时可以考虑增加分片数量如扩展到4库×4表引入读写分离结合Elasticsearch做复杂查询我们在实际项目中采用了分库分表ES的方案订单查询性能提升了20倍以上。具体实现是在订单创建时通过MQ异步将数据同步到ES集群。