一篇讲懂分库分表:概念、spirngboot实战

文章目录

很多刚入行做后端开发、数据库运维的新手朋友,工作久了总会听到大佬频繁聊分库分表分布式数据库主从复制这几个词。

平时开发小项目,单库单表写CRUD轻轻松松,压根不用操心这些,但一旦对接企业级业务,比如电商订单、用户账号、支付流水、物流记录这类数据量爆炸、并发超高的场景,单库单表立马就扛不住了。

很多新手最头疼的三个核心疑问,今天一次性掰开揉碎讲透:

1、到底什么是分库分表?核心作用是什么?

2、做了分库分表,数据库就算真正实现分布式了吗?二者到底啥关系?

3、分库分表和日常常做的主从复制,是互补还是替代?区别在哪?


一、先搞懂:为啥好好的单库单表,非要搞分库分表?

先不说专业术语,咱们用大白话举个生活例子,瞬间就能理解。

假设你开了一家超级火爆的线下连锁超市,初期顾客少,所有商品库存、收银账单、会员信息,全部记在一个账本上,一个收银员记账、对账完全够用,效率很高,简单好操作。

但随着超市生意爆火,问题很快就来了:

1、账本越来越厚,几百万条记录写满整本账本,翻账、查账、记账速度越来越慢;

2、所有活儿全靠一个收银员干,高峰期排队爆满,写入、查询全堵在一个人身上,扛不住高并发;

3、账本就一本,一旦弄丢、破损、出错,所有数据直接全没,风险极高,没有容错空间。

对应到数据库里就是一模一样的道理:

初期业务量小,单数据库、单数据表,写代码简单、维护方便,完全够用;

业务体量上来后,单表数据量破千万、破亿,单库每秒读写请求上万,就会出现三个致命瓶颈:

存储瓶颈:单表数据太多,索引失效,查询SQL越跑越慢,页面加载卡顿;

并发瓶颈:所有读写压力全压在一台数据库服务器上,CPU、内存、磁盘IO打满,系统频繁超时、宕机;

扩展瓶颈:单机数据库只能靠升级高配硬件续命,也就是垂直扩容,成本极高,而且硬件性能总有上限,没法无限升级。

分库分表,就是解决这三个痛点的核心方案:不换超高配硬件,而是把一本厚厚的大账本,拆成几十本小账本,分给多个收银员、多个柜台一起干活,分摊压力、拆分数据。


二、核心概念精讲:什么是分库?什么是分表?新手一看就懂

分库分表,拆开就是分库 + 分表两个操作,两者各司其职,解决的问题完全不一样,千万别混为一谈。

1、分表:拆数据表,解决「单表数据太多查询慢」

简单说:库还是那个库,表拆成很多张小表

比如业务原本只有一张 order 订单表,里面存了3年几十亿条订单数据,查询、新增、修改全卡顿。

分表之后,一张大表拆成 order\_01order\_02order\_03...order\_16 十几张小表。

所有订单数据按照固定规则打散存放,比如按用户ID取模、按时间月份拆分。

每一张小表数据量都很少,只有几百万条,索引好用,查询飞快,读写效率直接拉满。

分表核心作用:只解决单表数据量过大导致的查询、写入性能慢的问题,不拆分数据库服务器。

2、分库:拆数据库,解决「单库并发压力扛不住」

简单说:表结构不变,数据库拆成多个独立库,部署在不同服务器上

比如原本所有业务数据都存在唯一的一个主数据库 db\_main 里,所有读写请求都打在这一台服务器上,并发高了直接崩库。

分库之后,拆成 db\_order\_01db\_order\_02db\_user\_01db\_pay\_01 多个独立数据库,各自部署在不同物理服务器。

不同业务、不同分片的数据,各司其职存到不同库里,一台服务器扛不住的压力,分给十几台服务器一起扛。

分库核心作用:解决单台数据库服务器并发过高、硬件资源打满的瓶颈,分摊读写压力。

3、日常常说的「分库分表」完整版

绝大多数企业实战中,都是分库+分表组合使用:先分库、再分表,数据既拆服务器、又拆数据表,双重减负,完美适配大数据量、高并发业务场景。


三、核心灵魂问题:做了分库分表,就算分布式了吗?

直接给新手最核心、最扎心的标准答案:做了分库分表,不等于真正的分布式!

这是90%新手甚至初级开发都会搞混的知识点,一定要记牢。

1、分库分表的本质:单机数据库的「人工分片扩容手段」

不管你分了多少个库、拆了多少张表,哪怕拆几十上百个,每一个库、每一张底层数据库,还是传统的单机MySQL、单机关系型数据库

数据库本身没有分布式能力,不懂数据分片、不懂全局事务、不懂自动均衡,所有复杂逻辑:数据路由、分片规则、跨表跨库查询、事务一致性,全部要靠代码、中间件人工写代码、人工配置搞定

简单总结:分库分表 = 用人工手段,把一堆单机数据库,强行拼成一个看起来能用的"伪分布式存储"

2、真正的分布式数据库是什么?

像OceanBase、TiDB这类原生分布式数据库,内核天生就是分布式架构

不用你手动分库、不用你手动分表,不用你写路由规则,数据库内核自动帮你分片数据、自动扩容节点、自动处理分布式事务、自动均衡压力。

对开发来说,操作分布式数据库和操作单机MySQL一模一样,不用改业务代码,零感知扩容

3、一句话理清两者关系

分库分表:分布式存储的「过渡方案、低成本折中方案」,适合传统老项目改造,不想换数据库、不想大改架构;

分布式数据库:原生天生分布式,终极解决方案,适合超大规模业务,追求稳定、少运维、免人工分片。

不是做了分库分表就叫分布式,而是分库分表是走向分布式存储的一种初级实操方式。


四、分库分表 vs 主从复制:啥关系?互补还是替代?

这俩也是新手重灾区,很多人以为做了主从就不用分库分表,或者做了分库分表就不用主从,大错特错!两者完全不冲突,各司其职,必须搭配使用

1、先搞懂:主从复制是干啥的?

主从复制核心就两件事,不拆分数据,只备份、分流读请求

1、数据备份+高可用:一个主库负责写数据,多个从库实时同步主库数据,主库挂了从库顶上,数据不丢失,服务不宕机;

2、读写分离:主库专门负责新增、修改、删除写操作,从库专门负责查询读操作,分担主库读压力。

重点核心:主从复制,数据是全量一模一样的复制,不是拆分!

主库有多少数据,所有从库就同步多少数据,数据量一点没少,单表多大还是多大。

2、核心区别一眼看懂

主从复制 + 读写分离 :解决「数据库挂了咋办、读请求太多扛不住」,不解决数据量大、写并发瓶颈

分库分表 :解决「数据量太大、写并发太高」,不解决高可用、数据备份、读压力分流问题

3、企业标准架构:主从 + 分库分表一起用

正规企业实战架构都是一套组合拳:

第一步:先做分库分表,把大数据量、高并发写入拆分打散,解决存储和写入瓶颈;

第二步:每个拆分后的小库,再单独做主从复制+读写分离,保障每个分片库高可用、分担查询压力。

两者互补,缺一不可,谁也替代不了谁。


五、新手手把手实战:单表(order)分库分表基础落地实操(带代码+全注释)

前面理论看懂只是基础,新手最怕的就是:道理都懂,一行代码不会写,配置不会改,上线就出bug

这一节不搞虚的,选用企业最常用、新手上手最简单、无需额外搭建独立服务的Sharding-JDBC做分库分表实战。它是客户端轻量化中间件,直接嵌入项目代码,不用额外部署独立节点,配置简单、注释清晰,新手照着复刻就能跑通,完美适配SpringBoot+MySQL常规项目架构。

本次基础实战核心目标:搭建1库分8表订单order单表分片场景,不用多服务器,单机器就能模拟分表效果,学会核心分片逻辑、配置规则、代码编写,后续多表分片、扩容分库只需要改配置无需改代码。

1、实战前置准备(新手必看,一步不落下)

① 技术栈版本适配(新手避坑关键)

统一使用稳定通用版本,避免版本冲突报错,新手直接照搬即可:

✅ 开发框架:SpringBoot 2.7.x(稳定经典版,适配所有Sharding版本)

✅ 分表中间件:Sharding-JDBC 4.1.1(新手最友好,配置简单无复杂依赖)

✅ 数据库:MySQL 5.7/8.0 均可

✅ 持久层框架:MyBatis/MyBatis-Plus 通用适配

② 数据库和订单分表提前创建(分表规则:1库8表)

只创建一个数据库db\_order\_sharding,不做多库,先练熟单表分表核心逻辑;

在这个库里面创建8张结构完全一样的订单分表order\_0 ~ order\_7,所有表字段、主键、索引完全相同,只是数据存放分片不同。

分表SQL语句(直接复制执行即可):

sql 复制代码
-- 创建分库分表专属数据库
CREATE DATABASE IF NOT EXISTS db_order_sharding DEFAULT CHARACTER SET utf8mb4;

-- 循环创建8张订单分表 order_0 到 order_7(结构完全一致)
CREATE TABLE order_0 (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '订单主键自增ID',
    order_no VARCHAR(64) NOT NULL COMMENT '订单唯一编号',
    user_id BIGINT NOT NULL COMMENT '下单用户ID(分片核心字段)',
    goods_name VARCHAR(255) NOT NULL COMMENT '下单商品名称',
    order_amount DECIMAL(10,2) NOT NULL COMMENT '订单支付金额',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '订单创建时间',
    INDEX idx_user_id (user_id) COMMENT '用户ID索引,提升查询效率'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单分表0';

-- 依次复制上面SQL,修改表名order_1、order_2...order_7,全部执行创建即可
③ 核心分片规则设定(提前定死,后期不改)

采用新手最易理解、数据分布最均匀的用户ID哈希取模分片规则

分片计算公式:user_id % 8

💡 规则解释:用户ID对8取余数,余数是几,数据就存到对应的order_几分表中

举例:user_id=10,10%8=2 → 数据存入order_2表;user_id=17,17%8=1 → 数据存入order_1表,路由规则自动匹配,无需人工干预。

2、项目pom.xml依赖引入(带全注释,按需复制)

在SpringBoot项目核心配置文件中,引入数据库连接、MyBatis、Sharding-JDBC核心依赖,每个依赖都加注释,标注作用

xml 复制代码
<!-- SpringBoot核心父依赖,项目基础环境 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.15</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- SpringBoot web核心依赖,提供接口开发、网络请求基础能力 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- MySQL数据库连接驱动,适配8.0版本 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- MyBatis-Plus持久层框架,简化CRUD代码,不用手写SQL -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>

    <!-- 核心:Sharding-JDBC分库分表核心依赖,轻量化客户端分片中间件 -->
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        &lt;version>4.1.1</version>
    </dependency>

    <!-- 简化实体类代码,自动生成get/set方法,新手少写重复代码 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        &lt;optional>true</optional>
    </dependency>
</dependencies>

3、application.yml核心配置文件(单表order分片最全注释)

分库分表不用改业务代码,核心全在配置文件,下面每一行配置都带详细中文注释,新手看懂注释就懂分片原理。

yaml 复制代码
# SpringBoot项目核心配置
spring:
  # 数据源配置:绑定分库分表数据库连接信息
  datasource:
    # 数据库驱动类名称,MySQL8.0固定写法
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 连接地址,连接提前创建的分表专属数据库
    url: jdbc:mysql://localhost:3306/db_order_sharding?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
    # 数据库登录用户名,替换为自己的
    username: root
    # 数据库登录密码,替换为自己的
    password: 123456

# ###########################################
# Sharding-JDBC分表核心配置(新手重点看)
# ###########################################
shardingsphere:
  # 数据源分片配置
  sharding:
    # 配置分片表规则:逻辑表名 → 实际物理分表名
    tables:
      # 逻辑表名:订单业务虚拟表order
      order:
        # 实际物理分表规则:db_order_sharding库下的order_0到order_7
        actual-data-nodes: db_order_sharding.order_$->{0..7}
        # 分片策略配置
        database-strategy:
          none: # 本次实战只分表不分库,库级别不做分片
        table-strategy:
          inline:
            # 分片列:指定根据user_id用户ID做分片路由
            sharding-column: user_id
            # 分片算法:user_id % 8 取模运算,匹配对应分表
            algorithm-expression: order_$->{user_id % 8}
  # 开启SQL日志打印,新手必备:查看自动路由到哪张分表,方便排错调试
  props:
    sql.show: true

# MyBatis-Plus配置,扫描实体类、Mapper接口
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.sharding.entity

4、实体类、Mapper、业务代码编写(零改动,和单表写法一模一样)

① 订单实体类Order.java(带字段注释)
java 复制代码
package com.sharding.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 订单实体类
 * 注意:@TableName写逻辑表名order即可,不用写具体分表order_0~7
 * 分表路由由Sharding-JDBC自动完成,业务层无需感知
 */
@Data
@TableName("order")
public class Order {
    // 订单主键ID,自增
    @TableId(type = IdType.AUTO)
    private Long id;

    // 订单唯一编号
    private String orderNo;

    // 分片核心字段:用户ID,路由分表全靠这个字段
    private Long userId;

    // 下单商品名称
    private String goodsName;

    // 订单支付金额
    private BigDecimal orderAmount;

    // 订单创建时间
    private LocalDateTime createTime;
}
② Mapper接口、Service业务层(和单表CRUD完全无区别)

无需任何特殊代码,继承MyBatis-Plus基础接口即可,分表对代码完全透明,零侵入,这就是Sharding-JDBC的核心优势。

5、测试类实操测试(带注释,验证单表分片生效)

编写单元测试,新增多条不同userId的订单,查看日志自动路由到对应分表,验证分表实战效果。

java 复制代码
package com.sharding;
import com.sharding.entity.Order;
import com.sharding.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@SpringBootTest
public class ShardingTest {

    // 注入订单业务层
    @Autowired
    private OrderService orderService;

    @Test
    public void testAddOrder() {
        // 测试1:创建userId=10的订单  10%8=2 → 自动存入order_2表
        Order order1 = new Order();
        order1.setOrderNo("ORDER_20260504_001");
        order1.setUserId(10L); // 核心分片字段
        order1.setGoodsName("新手分库分表实战教程");
        order1.setOrderAmount(new BigDecimal("99.00"));
        order1.setCreateTime(LocalDateTime.now());
        // 插入数据,Sharding-JDBC自动路由对应分表
        orderService.save(order1);

        // 测试2:创建userId=17的订单  17%8=1 → 自动存入order_1表
        Order order2 = new Order();
        order2.setOrderNo("ORDER_20260504_002");
        order2.setUserId(17L); // 核心分片字段
        order2.setGoodsName("MySQL高性能优化手册");
        order2.setOrderAmount(new BigDecimal("89.00"));
        order2.setCreateTime(LocalDateTime.now());
        orderService.save(order2);
    }
}

六、重点进阶:多个表同时分表实操(order订单+user用户双表独立分片完整版)

很多新手学到单表分片后,核心刚需来了:项目不止一张大表,订单order、用户user、支付流水都要分表,不同表分片规则不一样,怎么配置、怎么实操?

核心核心结论先放前面:Sharding-JDBC支持多表独立分片,每张业务表单独配置分片规则、独立指定分片字段、独立设置分表数量,表与表之间互不干扰,业务代码依旧零改动,不用写任何特殊路由逻辑

本节以企业最常用的order订单表 + user用户表双表同时分表为例,手把手全流程实操,配置全覆盖、SQL全量、代码带注释,新手直接复刻就能运行,适配所有多表分片场景。

1、多表分片核心规划(双表独立规则,互不冲突)

沿用原有数据库 db\_order\_sharding,不用新建库,单库做多表分表,新手好上手:

① 订单表order分片规则(原有不变,延续之前逻辑)

分片字段:userId;分片规则:userId % 8;分表数量:order_0 ~ order_7 共8张表。

② 用户表user全新分片规则(独立自定义)

分片字段:id(用户主键ID);分片规则:id % 4;分表数量:user_0 ~ user_3 共4张表。

💡 关键特点:订单按用户ID分8表、用户按主键ID分4表,两张表规则完全独立、互不影响、各自路由,这就是多表分片的核心精髓。

2、新建用户分表SQL(直接复制执行,和订单表同库)

sql 复制代码
-- 在已有分表数据库db_order_sharding中,创建4张用户分表 user_0 ~ user_3
CREATE TABLE user_0 (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户主键ID(分片核心字段)',
    username VARCHAR(32) NOT NULL COMMENT '用户登录账号',
    phone VARCHAR(11) NOT NULL COMMENT '用户手机号',
    age INT COMMENT '用户年龄',
    register_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间',
    INDEX idx_username (username) COMMENT '账号索引,提升查询效率'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户分表0';

-- 依次复制上面SQL,修改表名user_1、user_2、user_3,全部执行创建即可

3、修改application.yml多表分片核心配置(关键!双表单独配置,全注释)

无需改依赖、无需改启动类、无需改原有订单代码,只需要在sharding分片tables节点下,新增user表独立分片配置即可,两张表各自匹配自己的路由规则,自动分流数据。

yaml 复制代码
# SpringBoot项目核心配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_order_sharding?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
    username: root
    password: 123456

# ###########################################
# Sharding-JDBC 多表分表核心配置(order+user双表独立分片)
# ###########################################
shardingsphere:
  sharding:
    tables:
      # 第一个分片表:订单order(原有配置完全不变,保留原有规则)
      order:
        actual-data-nodes: db_order_sharding.order_$->{0..7}
        database-strategy:
          none:
        table-strategy:
          inline:
            sharding-column: user_id
            algorithm-expression: order_$->{user_id % 8}
      # 第二个分片表:用户user(新增独立分片配置,和order互不干扰)
      user:
        # 用户表对应物理分表:db_order_sharding库下user_0~user_3
        actual-data-nodes: db_order_sharding.user_$->{0..3}
        # 只分表不分库,库级别无分片
        database-strategy:
          none:
        # 用户表专属独立分片策略
        table-strategy:
          inline:
            # 用户表分片字段:自身主键id,和订单表分片字段不一样
            sharding-column: id
            # 用户表专属分片算法:id % 4
            algorithm-expression: user_$->{id % 4}
  # 必开SQL日志,查看两张表各自路由情况,新手排错必备
  props:
    sql.show: true

# MyBatis-Plus配置保持不变
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.sharding.entity

4、新增用户实体类User.java(带分片核心注释)

java 复制代码
package com.sharding.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;

/**
 * 用户实体类(多表分片专属)
 * 注意:@TableName只写逻辑表名user,不用写user_0~3
 * 用户表分片字段为自身主键id,Sharding-JDBC自动按id%4路由分表
 */
@Data
@TableName("user")
public class User {
    // 用户主键ID,分片核心字段,路由全靠id
    @TableId(type = IdType.AUTO)
    private Long id;

    // 用户登录账号
    private String username;

    // 用户手机号
    private String phone;

    // 用户年龄
    private Integer age;

    // 用户注册时间
    private LocalDateTime registerTime;
}

5、多表分片统一测试类(同时测试订单+用户分表,验证各自路由)

测试代码无需任何分片特殊逻辑,新增订单、新增用户正常CRUD即可,框架自动按各自规则路由到对应分表,完美实现多表独立分片。

java 复制代码
package com.sharding;
import com.sharding.entity.Order;
import com.sharding.entity.User;
import com.sharding.service.OrderService;
import com.sharding.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@SpringBootTest
public class MultiShardingTest {

    // 注入订单业务层
    @Autowired
    private OrderService orderService;

    // 注入用户业务层
    @Autowired
    private UserService userService;

    // 测试多表同时分表生效,各自独立路由
    @Test
    public void testMultiTableSharding() {
        // ========== 1、测试订单表分片(按userId%8路由) ==========
        Order order = new Order();
        order.setOrderNo("ORDER_MULTI_001");
        order.setUserId(20L); // 20%8=4 → 存入order_4表
        order.setGoodsName("多表分表实战测试商品");
        order.setOrderAmount(new BigDecimal("199.00"));
        order.setCreateTime(LocalDateTime.now());
        orderService.save(order);

        // ========== 2、测试用户表分片(按id%4路由) ==========
        User user = new User();
        user.setUsername("zhangsan_test");
        user.setPhone("13800138000");
        user.setAge(25);
        user.setRegisterTime(LocalDateTime.now());
        // 主键id自动生成,自动按id%4路由到对应user分表
        userService.save(user);
    }
}

6、多表分片核心关键要点(新手必记,避坑核心)

每张表分片规则完全独立:order按userId分、user按id分,模数、分片字段随便自定义,互不影响;

业务代码零修改:不管加多少张分片表,实体类、CRUD代码和单表写法一模一样,无需适配分片逻辑;

配置新增不改动原有:新增一张表分表,只需要在yml的tables下加一段对应配置,不改动之前任何生效配置;

关联查询尽量业务层处理:多表分片后尽量避免跨分片表联表查询,提前在业务代码做关联适配,规避跨分片复杂SQL问题。

7、新手实战必避的5个实操坑(配置+代码双重避坑)

坑1:逻辑表和物理表名写错:代码只写逻辑表名,配置文件写真实物理分表,千万别写混;

坑2:分片字段随意修改:每张表分片字段一旦定义,增删改查必须携带,否则无法正常路由;

坑3:盲目一开始就分库+分表:新手先做多表分表,熟练后再升级多库多表,循序渐进;

坑4:关闭SQL日志:新手一定要开启sql.show=true,查看每张表路由详情,排错必备;

坑5:乱用分布式事务:单库多表无需分布式事务,跨库才需要,新手优先保证业务最终一致性。


七、终极进阶实战:多表「多库 + 多表」双分片(order订单、user用户各自分库分表)

前面咱们学会了:单库单表分表 → 单库多表分表

但企业真正上线,不是只分表,而是:不同业务表,不仅分表,还要分不同数据库

典型场景:

✅ 订单数据量巨大、写入并发高:订单要分库 + 分表

✅ 用户数据量大、查询频繁:用户也要分库 + 分表

订单和用户不在同一个数据库,互不影响,各自扩容

很多新手最怕的核心问题:不同表,分库规则不一样、分表规则也不一样,Sharding-JDBC怎么写?

直接给你核心结论:

Sharding-JDBC每张逻辑表都能独立配置:分库规则 + 分表规则,完全隔离,互不干扰,业务代码一行不改。


1、终极架构规划(企业生产标准)

① 总共拆4个数据库(模拟4台独立数据库服务器)

订单专属库:db_order_0、db_order_1(订单只走这两个库)

用户专属库:db_user_0、db_user_1(用户只走这两个库)

② 双层分片规则(各自独立,完全不打架)

👉 订单 order 规则

分库:userId % 2 路由到 db_order_0 / db_order_1

分表:userId % 8 每个库里再分8张表 order_0 ~ order_8

👉 用户 user 规则

分库:id % 2 路由到 db_user_0 / db_user_1

分表:id % 4 每个库里再分4张表 user_0 ~ user_3

💡 两张库互不串门,两张表规则完全不一样,这就是大型电商多业务分片标准玩法。


2、提前创建4个数据库 + 所有物理分表SQL(直接全量复制执行)

sql 复制代码
-- ========== 一、创建订单专属两个分库 + 内部各8张订单分表 ==========
CREATE DATABASE IF NOT EXISTS db_order_0 DEFAULT CHARACTER SET utf8mb4;
CREATE DATABASE IF NOT EXISTS db_order_1 DEFAULT CHARACTER SET utf8mb4;

-- db_order_0 库里创建 order_0 ~ order_7
CREATE TABLE db_order_0.order_0 (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '订单主键自增ID',
    order_no VARCHAR(64) NOT NULL COMMENT '订单唯一编号',
    user_id BIGINT NOT NULL COMMENT '下单用户ID(分片核心字段)',
    goods_name VARCHAR(255) NOT NULL COMMENT '下单商品名称',
    order_amount DECIMAL(10,2) NOT NULL COMMENT '订单支付金额',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '订单创建时间',
    INDEX idx_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 把上面表名依次建完:order_1 ~ order_7

-- db_order_1 库里同样创建 order_0 ~ order_7 结构一模一样


-- ========== 二、创建用户专属两个分库 + 内部各4张用户分表 ==========
CREATE DATABASE IF NOT EXISTS db_user_0 DEFAULT CHARACTER SET utf8mb4;
CREATE DATABASE IF NOT EXISTS db_user_1 DEFAULT CHARACTER SET utf8mb4;

-- db_user_0 库里创建 user_0 ~ user_3
CREATE TABLE db_user_0.user_0 (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户主键ID(分片字段)',
    username VARCHAR(32) NOT NULL COMMENT '用户账号',
    phone VARCHAR(11) NOT NULL COMMENT '手机号',
    age INT,
    register_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 依次创建 user_1、user_2、user_3
-- db_user_1 同样建 user_0 ~ user_3

3、pom.xml 必加Druid数据源(多库必备,前面加过就不用重复)

xml 复制代码
<!-- 多数据源连接池必须druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.16</version>
</dependency>

4、核心重点:application.yml 多库+多表、每张表独立分片完整配置(全注释)

业务代码完全不用改!只改配置!

每个逻辑表:单独数据源、单独分库算法、单独分表算法

yaml 复制代码
# ============ 多数据源配置:4个库全部注册 ============
spring:
  shardingsphere:
    datasource:
      names: ds_order0,ds_order1,ds_user0,ds_user1
      # 订单库0
      ds_order0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_order_0?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      # 订单库1
      ds_order1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_order_1?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      # 用户库0
      ds_user0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_user_0?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      # 用户库1
      ds_user1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_user_1?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456

    # ============ 分片核心:两张表【各自独立分库+分表】 ============
    sharding:
      tables:
        # 第一张大表:订单 order (2库8表)
        order:
          # 匹配所有物理节点:ds_order0/1 两个库,每个库order_0~7
          actual-data-nodes: ds_order$->{0..1}.order_$->{0..7}
          # 分库策略:按userId%2选库
          database-strategy:
            inline:
              sharding-column: user_id
              algorithm-expression: ds_order$->{user_id % 2}
          # 分表策略:按userId%8选表
          table-strategy:
            inline:
              sharding-column: user_id
              algorithm-expression: order_$->{user_id % 8}

        # 第二张大表:用户 user (2库4表,规则完全独立)
        user:
          # 匹配所有物理节点:ds_user0/1两个库,每个库user_0~3
          actual-data-nodes: ds_user$->{0..1}.user_$->{0..3}
          # 分库策略:按主键id%2分库
          database-strategy:
            inline:
              sharding-column: id
              algorithm-expression: ds_user$->{id % 2}
          # 分表策略:按主键id%4分表
          table-strategy:
            inline:
              sharding-column: id
              algorithm-expression: user_$->{id % 4}

    # 必开SQL日志,新手看路由排错
    props:
      sql.show: true

# mybatis配置不变
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.sharding.entity

5、实体类、Service、Mapper:一行代码不用改

不管你多少张表分库分表:

✅ 代码只操作逻辑表 order、user

✅ Sharding-JDBC 底层自动:选库 → 选表 → 执行SQL

✅ 开发完全无感知,和写单表一模一样


6、统一测试类(验证自动跨库+跨表路由)

java 复制代码
@SpringBootTest
public class AllShardingTest {

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserService userService;

    @Test
    public void testAll() {
        // userId=10
        // 分库:10%2=0 → ds_order0
        // 分表:10%8=2 → order_2
        Order order = new Order();
        order.setOrderNo("ORDER_KU_BIAO_001");
        order.setUserId(10L);
        order.setGoodsName("多库多表终极实战");
        order.setOrderAmount(new BigDecimal("199"));
        orderService.save(order);

        // 用户新增,主键id自动生成,自动按id分库分表
        User user = new User();
        user.setUsername("lisi_sharding");
        user.setPhone("13900139000");
        user.setAge(30);
        userService.save(user);
    }
}

7、多表多库分片黄金规则(新手永久收藏)

1、每一张业务大表,单独一套分库规则、单独一套分表规则,互不干扰;

2、order按userId分片、user按id分片,分片字段可以不一样

3、代码永远只写逻辑表,物理库、物理表全部交给配置;

4、能业务层关联,绝不跨库联表join

5、单库多表不需要分布式事务,多库跨库才需要分布式事务


八、全文新手核心总结

1、单表分表:解决单表数据量大;

2、多表分表:每张表单独配置分片规则;

3、多表+多库多分表:每张表可以单独分不同库、不同表规则,企业最终形态

4、Sharding-JDBC 核心:代码零侵入,全靠配置玩转所有分库分表

1、分库分表:传统单机数据库水平扩容手段,拆库拆表分摊数据和并发,解决大数据量、高并发瓶颈;

2、分库分表≠分布式:只是人工拼接的伪分布式,原生分布式数据库才是真正分布式架构;

3、分库分表vs主从复制:主从管高可用和读写分离,分库分表管数据拆分和写入扩容,两者必须搭配使用;

4、多表同时分表核心:多张业务表单独配置独立分片规则,表与表互不干扰,代码零侵入,配置新增不改动原有逻辑,企业多表分片全靠这种方式落地。

相关推荐
梦想画家1 小时前
PostgreSQL 物化视图实战:从数据固化到智能刷新的全链路指南
数据库·postgresql·物化视图
weoptions2 小时前
简单sql注入中如何通过简单语句判断注入类型&注入方法
数据库·sql
小短腿的代码世界2 小时前
Qt数据库编程深度解析:从SQL基础到ORM架构设计
数据库·sql·qt
Database_Cool_2 小时前
在 RDS PostgreSQL 中实现 RaBitQ 量化
数据库·阿里云·ai·postgresql
【心态好不摆烂】2 小时前
MySQL操作库
数据库·mysql
Javatutouhouduan2 小时前
Java小白如何快速玩转Redis?
java·数据库·redis·分布式锁·java面试·后端开发·java程序员
Lyyaoo.4 小时前
Redisson
数据库·缓存
网络工程小王4 小时前
【LCEL 链式调用详解】调用篇-2
java·服务器·前端·数据库·人工智能
道法自然,人法天5 小时前
PostgreSQL安装与初始化教程(二进制压缩包)
数据库·postgresql