这篇文章的核心,就是讲,springboot在操作数据库的时候
为什么要去进行分库分表
如何在技术栈配置的时候,实现分库分表
一主多从何多主多从,其实本质上是在架构,机器层面实现三高
而分库分表是在数据层面实现三高
高可用,不太适用,但是高性能,高并发就好了
你的理解非常到位,而且一针见血地指出了分库分表与主从复制的本质区别。我们来把这篇文章的核心逻辑彻底捋顺,并补全**技术栈配置(以ShardingSphere-JDBC为例)**的具体实现细节。
1. 核心本质:架构分层与"三高"分工
你总结得极对:
- 主从复制(一主多从/多主多从) 是**"机器/架构层"的横向扩展。它解决的是 高可用(HA)和 读高并发**(读写分离)。但它的痛点是写性能依然受限于单主节点,且无法解决单表数据量过大的问题。
- 分库分表(Sharding) 是**"数据层"的横向扩展。它解决的是 海量数据存储和写高并发**(将写压力打散)。
关于"高可用"的细化: 你说"高可用不太适用"非常精准。分库分表本身不提供高可用 ,反而会引入分布式故障风险。真正的生产环境,一定是**"分库分表 + 主从复制"结合**:即每个分片(库)内部再搭建主从集群,用主从保高可用 ,用分片保高性能/高并发。
2. 为什么要分库分表?(触发阈值)
在Spring Boot中,当出现以下硬性指标时,就必须考虑:
- 单表数据量 :MySQL单表建议不超过 500万~1000万 行(或磁盘容量达20GB)。超过后,B+树索引层级加深,磁盘IO剧增,即使命中索引,查询延迟也会从毫秒级恶化到秒级。
- 单库连接数:Spring Boot的HikariCP连接池通常设为核心数*2+1。单库最大连接数约1000个,若微服务实例过多,连接池会成为瓶颈。
- 写入TPS :单库写入TPS受限于Redo Log和Binlog的刷盘,通常上限在 2000~3000 TPS 左右。
3. 如何在Spring Boot技术栈中实现?(以ShardingSphere-JDBC为例)
目前最主流的实现是 Apache ShardingSphere-JDBC(Sphere-JDBC),它以轻量级Jar包形式注入Spring Boot,无需额外部署Proxy。
核心配置逻辑(YAML / Properties):
第一步:引入依赖 (Maven)
xml
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.3.2</version>
</dependency>
第二步:配置数据源(分库分表规则)
这里以**订单表(order)**按 user_id 取模分4个库,按 order_id 取模分4张表为例。
yaml
spring:
shardingsphere:
datasource:
names: ds0, ds1, ds2, ds3 # 逻辑数据源名
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_order_0
username: root
password: 123456
# ds1, ds2, ds3 配置类似,指向不同的库 ...
rules:
sharding:
tables:
t_order: # 逻辑表名(Spring Boot Mapper里操作这个名)
actual-data-nodes: ds$->{0..3}.t_order_$->{0..3} # 实际节点映射
# 分库策略
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: mod-db
# 分表策略
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: mod-table
sharding-algorithms:
mod-db:
type: MOD
props:
sharding-count: 4 # 分库数量
mod-table:
type: MOD
props:
sharding-count: 4 # 分表数量
# 分布式主键生成(避免雪花算法ID冲突)
key-generators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 1
第三步:Spring Boot 业务代码零侵入
配置完成后,你的 Mapper 完全不需要改动,依然像操作单表一样注入和使用:
java
@Mapper
public interface OrderMapper {
// 插入时,ShardingSphere会根据user_id自动路由到对应库,根据order_id自动路由到对应表
@Insert("INSERT INTO t_order (user_id, order_id, amount) VALUES (#{userId}, #{orderId}, #{amount})")
int insert(Order order);
}
4. 配置时的"三大致命陷阱"(文章必提的重点)
在技术选型和配置时,必须解决这三个核心问题:
- 分片键(Sharding Key)必须携带 :增删改查的SQL的
WHERE条件中必须包含 分片键(如user_id)。如果不带,ShardingSphere会执行全路由(广播),遍历所有库表,性能直接崩溃。 - 跨库事务(分布式事务) :分库后,本地事务失效。若业务强一致性要求(如订单扣库存),需引入 Seata(XA/TCC) ;若弱一致性,可使用ShardingSphere自带的 柔性事务(BASE)。
- 分布式ID唯一性 :不能依赖数据库自增ID(不同库会重复)。必须使用 雪花算法(Snowflake) 或 美团Leaf 生成全局唯一ID,且该ID常作为分表键,保证数据均匀落盘。
5. 总结:你们的架构演进路线图
文章中最后可以给出一个标准的演进结论:
- 初期:单库单表 + 主从(读写分离)。
- 中期(数据量<500万,写QPS<2000) :只分表不分库,解决单表锁和索引性能问题。
- 后期(数据量破亿,写QPS飙升) :分库分表 + 主从副本 (每个分片库都配备一主一从)。此时,分库分表扛写流量和存储量 ,主从复制扛读流量和容灾高可用。
你需要特别注意:Spring Boot配置的核心,其实就是在application.yml中定义好**"逻辑表"与 "真实数据节点"的映射规则,以及分片算法**。一旦配好,代码层面完全无感------这也是Spring Boot生态推崇的"配置即服务"的精髓。