在 Spring Boot 中配置 ShardingSphere 实现分库分表与读写分离
随着业务数据量和访问压力的增长,单体数据库架构逐渐面临性能瓶颈与扩展性问题。为了应对这一挑战,常见的解决方案包括读写分离与分库分表:前者用于缓解读写压力不均,后者用于降低单表数据规模,提高整体查询与写入性能。
在实际开发中,如果直接在业务代码中实现路由逻辑,会显著增加系统复杂度。因此,通常会引入 ShardingSphere 这类数据库中间件,在不改动业务代码的前提下完成 SQL 路由与数据拆分。
本文将基于 Spring Boot,逐步实现 ShardingSphere 的读写分离与分库分表配置,并通过示例验证其运行效果。
先决条件
配置好 MySQL 主从,参考 MySQL 主从复制 一文中配置 MySQL 主从复制,主机用来写,从机用来读。
数据库中有测试用表:
1 2 3 4 5 6 7 8 9 10 11create table users ( id bigint auto_increment comment '用户ID' primary key, email varchar(255) not null comment '用户邮箱', nickname varchar(50) not null comment '用户昵称', password_hash varchar(255) not null comment '用户密码', constraint uk_email unique (email) ) comment '用户表';使用 MybatisPlus 3 操作数据库 (可以通过插件例如 MybatisX 一键生成 mapper 和 domain 等)
读写分离
在 Spring Boot 项目中的 application.yaml 中配置数据库驱动和 jdbc url
| |
在与 application.yaml 同目录下创建 sharding.yaml 文件写入如下:
| |
配置成功后启动 Spring Boot 项目检查无误后进行测试 Sharding jdbc 读写分离是否正常运行,创建 Spring Boot 测试类:
| |
分别测试每个方法,正确输出如下:
testInsert()
| |
testSelect()
| |
testTransactionalRead()
| |
testForceMaster()
| |
全部测试通过,读写分离配置完成
分库分表
首先配置 mysql 主从复制和测试用数据库
创建三个文件
master-init.sql1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66-- ===== 建库授权 ===== CREATE DATABASE IF NOT EXISTS db_0; CREATE DATABASE IF NOT EXISTS db_1; GRANT ALL PRIVILEGES ON db.* TO 'user'@'%'; GRANT ALL PRIVILEGES ON db_0.* TO 'user'@'%'; GRANT ALL PRIVILEGES ON db_1.* TO 'user'@'%'; -- 创建主从复制专用账号 CREATE USER IF NOT EXISTS 'replicator'@'%' IDENTIFIED BY 'replicator123'; GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%'; FLUSH PRIVILEGES; -- ===== db:非分片表 ===== USE db; CREATE TABLE roles ( id bigint PRIMARY KEY, type varchar(50) NOT NULL ); CREATE TABLE user_profile ( user_id bigint PRIMARY KEY, avatar varchar(255), bio varchar(500), gender tinyint DEFAULT 0, birthday date, location varchar(100) ); CREATE TABLE user_role ( user_id bigint NOT NULL, role_id bigint NOT NULL, PRIMARY KEY (user_id, role_id) ); CREATE TABLE outbox ( id bigint PRIMARY KEY, topic varchar(100) NOT NULL, payload text NOT NULL, sent tinyint DEFAULT 0 NOT NULL, created_at datetime NOT NULL ); INSERT INTO roles (id, type) VALUES (1, 'admin'), (2, 'user'); -- ===== db_0:users 分片表 ===== USE db_0; CREATE TABLE users_0 ( id bigint PRIMARY KEY, email varchar(255) NOT NULL UNIQUE, nickname varchar(50) NOT NULL, password_hash varchar(255) NOT NULL ); CREATE TABLE users_1 LIKE users_0; -- ===== db_1:users 分片表 ===== USE db_1; CREATE TABLE users_0 ( id bigint PRIMARY KEY, email varchar(255) NOT NULL UNIQUE, nickname varchar(50) NOT NULL, password_hash varchar(255) NOT NULL ); CREATE TABLE users_1 LIKE users_0;slave-init.sh1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21#!/bin/bash echo "等待 master 就绪..." until mysql -h mysql-master -P 3306 -u replicator -preplicator123 -e "SELECT 1" &>/dev/null; do echo "重试中..." sleep 3 done mysql -uroot -p"$MYSQL_ROOT_PASSWORD" <<EOF STOP REPLICA; CHANGE REPLICATION SOURCE TO SOURCE_HOST='mysql-master', SOURCE_PORT=3306, SOURCE_USER='replicator', SOURCE_PASSWORD='replicator123', SOURCE_AUTO_POSITION=1, GET_SOURCE_PUBLIC_KEY=1; START REPLICA; EOF echo "主从复制配置完成"docker-compose.yaml
| |
使用 docker compose up -d 启动,并进入 mysql-slave 从机中查看状态 docker exec -it mysql-slave mysql -uroot -proot,
| |
输出:
| |
状态正常,可以进行 sharding sphere 分库分表配置,修改 sharding.yaml,
| |
配置完后运行测试,
| |
控制台输出:
| |
20 条测试数据全部插入数据库成功,进入数据库查看
db_0.users_0
| id | nickname | password | |
|---|---|---|---|
| 4 | user_3@test.com | user3 | pwd_3 |
| 8 | user_7@test.com | user7 | pwd_7 |
| 12 | user_11@test.com | user11 | pwd_11 |
| 16 | user_15@test.com | user15 | pwd_15 |
| 20 | user_19@test.com | user19 | pwd_19 |
db_0.users_1
| id | nickname | password | |
|---|---|---|---|
| 2 | user_1@test.com | user1 | pwd_1 |
| 6 | user_5@test.com | user5 | pwd_5 |
| 10 | user_9@test.com | user9 | pwd_9 |
| 14 | user_13@test.com | user13 | pwd_13 |
| 18 | user_17@test.com | user17 | pwd_17 |
db_1.users_0
| id | nickname | password | |
|---|---|---|---|
| 1 | user_0@test.com | user0 | pwd_0 |
| 5 | user_4@test.com | user4 | pwd_4 |
| 9 | user_8@test.com | user8 | pwd_8 |
| 13 | user_12@test.com | user12 | pwd_12 |
| 17 | user_16@test.com | user16 | pwd_16 |
db_1.users_1
| id | nickname | password | |
|---|---|---|---|
| 3 | user_2@test.com | user2 | pwd_2 |
| 7 | user_6@test.com | user6 | pwd_6 |
| 11 | user_10@test.com | user10 | pwd_10 |
| 15 | user_14@test.com | user14 | pwd_14 |
| 19 | user_18@test.com | user18 | pwd_18 |
如上可见 20 条 user 数据被正确分到了四张表中,分库分表配置成功。
通过上述示例可以看到,数据在插入时已经按照分片规则被自动路由到不同的库和表中,实现了基础的分库分表效果。
但需要注意的是,本文中的分片规则属于人为构造的简化模型,更多用于帮助理解数据路由过程。在真实生产环境中,ShardingSphere 还支持更复杂的分片策略(如哈希分片、范围分片、自定义算法等),同时也可以配合雪花算法等分布式 ID 生成方案,从而避免手动维护 ID 和路由规则的问题。