2026/4/5 19:47:44
网站建设
项目流程
温州市瓯海建设局网站,微信公众 wordpress,营销型企业网站建设案例,会网站开发没学历视频看了几百小时还迷糊#xff1f;关注我#xff0c;几分钟让你秒懂#xff01;在高并发、大数据量的业务场景中#xff0c;单库单表很容易成为性能瓶颈。为了解决这个问题#xff0c;“分库分表”成了后端开发绕不开的话题。而 Sharding-JDBC#xff08;现更名为 Shard…视频看了几百小时还迷糊关注我几分钟让你秒懂在高并发、大数据量的业务场景中单库单表很容易成为性能瓶颈。为了解决这个问题“分库分表”成了后端开发绕不开的话题。而Sharding-JDBC现更名为ShardingSphere-JDBC作为 Apache 顶级项目是 Java 生态中最主流的分库分表中间件之一。本文将带你从零基础到实战落地使用Java Spring Boot搭建一个完整的分库分表案例并讲解为什么用、怎么用、反例避坑让小白也能一目了然一、需求场景为什么要分库分表 场景描述假设你正在开发一个电商平台的订单系统日均订单量50万单表数据量超过 2000 万行查询变慢、写入延迟、备份困难、主从同步压力大……这时候单库单表已经扛不住了✅ 解决方案分库分表分库Database Sharding把数据分散到多个数据库实例减轻单库压力。分表Table Sharding把一张大表拆成多张小表提升查询效率。举个例子1亿条订单数据 → 拆成 2 个库 × 4 张表 8 份每份仅 1250 万条。二、Sharding-JDBC 是什么Sharding-JDBC 是客户端直连数据库的轻量级 Java 框架以JDBC 驱动的形式嵌入应用对业务代码几乎无侵入。✅ 优点轻量、高性能、无需额外部署中间件❌ 缺点不支持跨库复杂 JOIN、事务需谨慎处理它属于ShardingSphere生态的一部分还有 Sharding-Proxy代理模式等但 JDBC 模式最适合 Spring Boot 应用。三、实战Spring Boot Sharding-JDBC 分库分表1️⃣ 环境准备JDK 17Spring Boot 3.2.xMySQL 8.0本地或 DockerMaven2️⃣ 数据库设计模拟 2 库 4 表-- 创建两个数据库 CREATE DATABASE order_db_0; CREATE DATABASE order_db_1; -- 在每个库中创建两张订单表 USE order_db_0; CREATE TABLE t_order_0 (order_id BIGINT PRIMARY KEY, user_id BIGINT, amount DECIMAL(10,2)); CREATE TABLE t_order_1 (order_id BIGINT PRIMARY KEY, user_id BIGINT, amount DECIMAL(10,2)); USE order_db_1; CREATE TABLE t_order_0 (order_id BIGINT PRIMARY KEY, user_id BIGINT, amount DECIMAL(10,2)); CREATE TABLE t_order_1 (order_id BIGINT PRIMARY KEY, user_id BIGINT, amount DECIMAL(10,2));分片规则库分片键user_id % 2→ 决定进order_db_0还是order_db_1表分片键order_id % 2→ 决定进t_order_0还是t_order_13️⃣ Spring Boot 项目搭建pom.xml 依赖dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.apache.shardingsphere/groupId artifactIdshardingsphere-jdbc-core-spring-boot-starter/artifactId version5.4.0/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency /dependencies注意ShardingSphere 5.x 起包名从io.shardingsphere改为org.apache.shardingsphereapplication.yml 配置核心spring: shardingsphere: # 数据源配置 datasource: names: ds0,ds1 ds0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/order_db_0?useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password ds1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/order_db_1?useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password # 分片规则 rules: sharding: tables: t_order: actual-data-nodes: ds$-{0..1}.t_order_$-{0..1} table-strategy: standard: sharding-column: order_id sharding-algorithm-name: table-inline database-strategy: standard: sharding-column: user_id sharding-algorithm-name: db-inline sharding-algorithms: db-inline: type: INLINE props: algorithm-expression: ds$-{user_id % 2} table-inline: type: INLINE props: algorithm-expression: t_order_$-{order_id % 2} # 打印 SQL调试用 props: sql-show: true4️⃣ 实体类与 Mapper// Order.java public class Order { private Long orderId; private Long userId; private BigDecimal amount; // getter/setter... }// OrderMapper.java使用 MyBatis 或 JPA 均可这里简化用 JdbcTemplate Repository public class OrderMapper { Autowired private JdbcTemplate jdbcTemplate; public void insert(Order order) { String sql INSERT INTO t_order (order_id, user_id, amount) VALUES (?, ?, ?); jdbcTemplate.update(sql, order.getOrderId(), order.getUserId(), order.getAmount()); } public ListOrder findByUserId(Long userId) { String sql SELECT * FROM t_order WHERE user_id ?; return jdbcTemplate.query(sql, (rs, rowNum) - new Order( rs.getLong(order_id), rs.getLong(user_id), rs.getBigDecimal(amount) ), userId); } }注意SQL 中写的是逻辑表名t_orderSharding-JDBC 会自动路由到真实表。5️⃣ 测试 ControllerRestController public class OrderController { Autowired private OrderMapper orderMapper; PostMapping(/order) public String createOrder(RequestBody Order order) { orderMapper.insert(order); return Order inserted!; } GetMapping(/orders/{userId}) public ListOrder getOrders(PathVariable Long userId) { return orderMapper.findByUserId(userId); } }6️⃣ 测试效果插入userId1001, orderId10001→user_id % 2 1→ 库ds1→order_id % 2 1→ 表t_order_1✅ 数据写入order_db_1.t_order_1查询userId1001→ 自动路由到ds1并扫描t_order_0和t_order_1因为不知道 order_id✅ 返回所有该用户订单控制台会打印实际执行的 SQL验证是否命中正确库表。四、反例 常见错误避坑指南❌ 反例1不分片键直接查全表// 错误没有分片键会广播查询所有库所有表 ListOrder all jdbcTemplate.query(SELECT * FROM t_order, ...);后果8 个表全查性能爆炸✅ 正确做法尽量带分片键如user_id查询。❌ 反例2跨库事务不处理Transactional public void transfer(Order order1, Order order2) { orderMapper.insert(order1); // 可能写入 ds0 orderMapper.insert(order2); // 可能写入 ds1 }Sharding-JDBC 默认使用本地事务跨库时无法保证 ACID✅ 解决方案使用Seata等分布式事务框架或避免跨库写入通过业务设计如按 user_id 聚合❌ 反例3ORDER BY / GROUP BY 跨分片性能差SELECT user_id, SUM(amount) FROM t_order GROUP BY user_id;如果user_id不是分片键会从所有分片拉数据到内存聚合OOM 风险✅ 建议聚合操作尽量在单分片内完成或使用异步数仓。五、注意事项总结项目说明分片键选择必须高频查询字段如 user_id、tenant_id避免全表扫描不带分片键的查询慎用事务范围跨库事务需额外处理JOIN 限制仅支持同一分片内的表 JOIN自增 ID建议用雪花算法ShardingSphere 提供SNOWFLAKE算法版本兼容Spring Boot 3 JDK 17 请用 ShardingSphere 5.3六、结语分库分表不是银弹但在数据量爆炸时是必经之路。Sharding-JDBC 以其轻量、易集成、高性能的特点成为 Spring Boot 项目的首选方案。只要掌握分片规则设计 避开跨库陷阱你就能轻松驾驭千万级数据视频看了几百小时还迷糊关注我几分钟让你秒懂