咱就是说,做开发最怕啥?怕上线前老板拍胸脯说“咱这项目撑死百来个用户”,结果半年后用户飙到千万,数据库直接给你摆烂——查询卡到超时,插入慢到转圈,监控面板红得像过年的鞭炮,运维小哥拿着键盘追着你问“这表都千万行了,你咋不早做准备?”
别慌!今天就给大伙整一个“救命套餐”——SpringBoot + ShardingSphere 分库分表实战。手把手教你把一个濒临“猝死”的MySQL,改造成能扛千万用户数据的“硬汉”,还附带可直接跑的Demo,看完就能抄作业!
先声明:这篇文章没有晦涩的理论堆砌,全是大白话+实战干货,哪怕你是刚接触分库分表的“小白”,也能看得明明白白。
一、先唠唠:为啥非要搞分库分表?
在聊技术之前,先给那些还在“裸奔”的兄弟提个醒:单库单表不是不能用,是扛不住“用户爆炸式增长”。就像你家小电驴,平时买菜代步没问题,让它拉十吨货,不趴窝才怪!
单库单表的致命问题:
磁盘扛不住:一张千万行的表,光数据文件就好几个G,查询时磁盘IO直接拉满,比蜗牛爬还慢;
索引扛不住:索引文件也跟着变大,查询时走索引都要扫半天,更别说全表扫描了(全表扫描=直接宣判死刑);
并发扛不住:MySQL单库的并发连接数有限,上千个请求同时打过来,直接“堵车”,后面的请求全排队超时。
而分库分表,本质就是“拆大活”——把一个超大的库拆成多个小库,一个超大的表拆成多个小表,让每个小库小表都“轻装上阵”。就像把十吨货分成十个小包裹,每个小电驴拉一吨,效率直接拉满!
今天的主角 ShardingSphere,就是一个“拆活小能手”,不用你手动管理多个库表,它帮你封装好一切,你写SQL的时候还跟单库单表一样,爽得很!
二、实战Demo:手把手教你搭环境
话不多说,直接上硬菜。咱们以“用户表”为例,实现「分库+分表」:
需求:千万用户数据,按用户ID取模分2个库(db0、db1),每个库再按用户ID取模分3个表(user_0、user_1、user_2),最终共2库6表。
1. 环境准备(先备齐“食材”)
JDK 8+(别用太新的,稳定为主);
SpringBoot 2.7.x(主流版本,踩坑少);
ShardingSphere-JDBC 5.1.x(核心依赖,分库分表全靠它);
MySQL 8.0(两个库:db0、db1,每个库建3张用户表);
Maven(管理依赖,别手动下JAR包,会累死人)。
2. 建库建表(先搭好“架子”)
先手动建两个库(db0、db1),然后在每个库下执行以下SQL建3张用户表(user_0、user_1、user_2):
-- 以db0为例,db1执行同样的SQL CREATE DATABASE IF NOT EXISTS db0 DEFAULT CHARACTER SET utf8mb4; USE db0; -- 用户表(分表后缀0、1、2) CREATE TABLE IF NOT EXISTS user_0 ( id BIGINT NOT NULL COMMENT '用户ID', username VARCHAR(50) NOT NULL COMMENT '用户名', phone VARCHAR(20) NOT NULL COMMENT '手机号', create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表(分表0)'; CREATE TABLE IF NOT EXISTS user_1 LIKE user_0; CREATE TABLE IF NOT EXISTS user_2 LIKE user_0; -- db1同理,创建db1库,再建user_0、user_1、user_2三张表提示:不用纠结表结构简单,核心是演示分库分表逻辑,实际项目里按需加字段就行。
3. 项目搭建(核心步骤,抄作业就行)
3.1 引入依赖(pom.xml)
核心依赖就3个:SpringBoot核心、ShardingSphere-JDBC、MySQL驱动,其他依赖按需加(比如MyBatis-Plus,简化CRUD):
<dependencies> <!-- SpringBoot核心 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- ShardingSphere-JDBC 核心依赖 --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>5.1.2</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- MyBatis-Plus 简化CRUD(可选,JPA也能凑活) --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <!-- lombok 省掉getter/setter(懒人必备) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>3.2 配置分库分表规则(application.yml)
这是核心中的核心!告诉ShardingSphere:哪个库是数据源、按什么规则分库、按什么规则分表。注释写得很清楚,照着改就行:
spring: shardingsphere: # 数据源配置(两个库:db0、db1) datasource: names: db0,db1 # 数据源名称,用逗号分隔 # db0 配置 db0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db0?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root # 你的MySQL用户名 password: root # 你的MySQL密码 # db1 配置(和db0类似,只是库名不同) db1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db1?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root password: root # 分库分表规则配置 rules: sharding: # 分库规则(按user_id取模分库:user_id%2=0→db0,user_id%2=1→db1) databases: # 逻辑库名(随便起,和代码里的表名对应) user_db: database-strategy: standard: sharding-column: id # 分库字段(用户ID) sharding-algorithm-name: db_inline # 分库算法名称(和下面对应) # 分表规则(按user_id取模分表:user_id%3=0→user_0,以此类推) tables: # 逻辑表名(随便起,代码里操作这个表名就行) t_user: actual-data-nodes: user_db_${0..1}.user_${0..2} # 实际表:db0/db1下的user_0~user_2 table-strategy: standard: sharding-column: id # 分表字段(用户ID) sharding-algorithm-name: table_inline # 分表算法名称(和下面对应) # 分片算法配置(inline表达式,简单高效) sharding-algorithms: # 分库算法(user_id%2 → 0或1,对应db0、db1) db_inline: type: INLINE props: algorithm-expression: db${id % 2} # 分表算法(user_id%3 → 0、1、2,对应user_0~user_2) table_inline: type: INLINE props: algorithm-expression: user_${id % 3} # 打印SQL(调试用,生产环境可以关掉) props: sql-show: true # 端口号(随便设,不冲突就行) server: port: 80803.3 编写实体类、Mapper(CRUD基础操作)
用MyBatis-Plus简化操作,不用写XML文件,直接注解搞定:
// 实体类(和表结构对应) @Data @TableName("t_user") // 这里的表名是application.yml里的逻辑表名! public class User { private Long id; // 用户ID(分库分表字段) private String username;// 用户名 private String phone; // 手机号 private LocalDateTime createTime; // 创建时间 } // Mapper接口(继承BaseMapper,自带CRUD方法) @Mapper public interface UserMapper extends BaseMapper<User> { // 不用写额外方法,BaseMapper里有insert、selectById、selectList等方法 } // 启动类(加上@MapperScan,扫描Mapper接口) @SpringBootApplication @MapperScan("com.example.shardingdemo.mapper") // 改成你的Mapper包路径 public class ShardingDemoApplication { public static void main(String[] args) { SpringApplication.run(ShardingDemoApplication.class, args); } }3.4 编写测试接口(验证分库分表效果)
写两个接口:一个新增用户,一个查询用户,看看数据是不是真的分到了对应的库表:
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserMapper userMapper; // 新增用户(测试分库分表插入) @PostMapping("/add") public String addUser(@RequestBody User user) { // 这里的id最好是雪花算法生成的分布式ID(保证唯一且有序) // 为了演示,咱们手动传id(比如1、2、3...) user.setCreateTime(LocalDateTime.now()); userMapper.insert(user); return "新增成功!用户ID:" + user.getId(); } // 根据ID查询用户(测试分库分表查询) @GetMapping("/{id}") public User getUserById(@PathVariable Long id) { // ShardingSphere会自动根据id找对应的库表,不用你手动指定! return userMapper.selectById(id); } // 批量新增(测试批量插入效果) @PostMapping("/batchAdd") public String batchAdd() { for (long i = 1; i <= 10; i++) { User user = new User(); user.setId(i); user.setUsername("测试用户" + i); user.setPhone("1380013800" + (i % 10)); user.setCreateTime(LocalDateTime.now()); userMapper.insert(user); } return "批量新增10个用户成功!"; } }4. 测试效果(见证奇迹的时刻)
启动项目,用Postman或浏览器调用接口,然后去MySQL里看数据分布:
调用批量新增接口:http://localhost:8080/user/batchAdd
查看数据分布:
db0库(id%2=0):会有id=2、4、6、8、10的用户,分别存在user_0(2%3=2?不对,2%3=2→user_2;4%3=1→user_1...自己算哈);
db1库(id%2=1):会有id=1、3、5、7、9的用户,同样按id%3分到不同表;
调用查询接口:http://localhost:8080/user/1,ShardingSphere会自动去db1库找对应的表,返回数据。
看到数据自动分到不同库表的那一刻,是不是觉得:这波操作,稳了!
三、ShardingSphere:优点很突出,缺点也很“扎心”
用了这么久ShardingSphere,咱客观聊聊它的优缺点。优点让人爱到不行,缺点也得提前避坑!
1. 优点:为啥大家都爱用?
「透明化操作」:这是最大的亮点!你写SQL的时候,完全不用管数据在哪个库哪个表,就跟操作单库单表一样,ShardingSphere自动帮你路由到目标库表。不用改业务代码,这波血赚;
「功能超全」:支持分库、分表、读写分离、数据加密、分布式事务...基本上你能想到的数据库中间件需求,它都能满足,不用再搭一堆组件;
「兼容性强」:支持MySQL、PostgreSQL、Oracle等主流数据库,还支持MyBatis、JPA等ORM框架,接入成本极低;
「扩展性好」:后续数据量再涨,想增加库表数量,只要修改分片规则,不用动历史数据(当然,历史数据迁移另说,但至少扩展方便)。
2. 缺点:这些坑要提前避开!
「复杂SQL容易翻车」:简单的CRUD没问题,但如果是复杂的SQL(比如多表关联、子查询、聚合函数),ShardingSphere可能会路由错误,或者直接不支持。建议写复杂SQL前,先查官方文档,或者做好测试;
「分布式事务是个坎」:虽然支持分布式事务(比如XA、SAGA模式),但性能和稳定性不如单库事务。如果你的业务对事务一致性要求极高,建议谨慎使用,或者用其他方案(比如最终一致性);
「运维成本增加」:分库分表后,库表数量变多,监控、备份、故障排查都比单库单表复杂。比如某个表出问题,你得先找到它在哪个库,再定位问题;
「分片规则一旦定了,难修改」:比如你一开始按user_id取模分表,后来想改成按地域分表,那历史数据迁移就是个大工程。所以,分片规则一定要提前设计好,别拍脑袋决定!
四、最后总结:什么时候该用ShardingSphere?
如果你家项目遇到以下情况,别犹豫,直接上ShardingSphere:
单库单表数据量超过500万(MySQL的性能拐点),查询开始变慢;
并发量越来越高,单库扛不住,需要水平扩展;
想做读写分离,提高查询性能,但又不想改业务代码。
最后再叮嘱一句:分库分表不是银弹,能不分就不分!如果能通过优化索引、SQL、缓存解决问题,就先别搞分库分表。只有当这些手段都没用了,再考虑分库分表。
好了,今天的实战教程就到这。Demo代码已经给大家了,直接抄作业就行。如果运行过程中遇到问题,评论区留言,咱一起解决!
最后求个赞!创作不易,你的点赞就是我更新的动力~ 比心!