Spring Boot + ShardingSphere 實現分庫分表 + 讀寫分離實戰

🚀 Spring Boot + ShardingSphere 實現分庫分表 + 讀寫分離(涵蓋99%真實場景)

🏷? 標簽:ShardingSphere、分庫分表、讀寫分離、MySQL 主從、Spring Boot 實戰

分庫分表 vs 讀寫分離 vs 主從配置與數據庫高可用架構區別


📚 目錄導航

  • 🔍 一、場景說明
  • 🧱 二、架構圖
  • ?? 三、核心配置
  • 🗃? 四、數據庫建表SQL
  • 👨?💻 五、關鍵代碼
  • 🧪 六、測試驗證
  • 🧠 七、總結與建議

🔍 一、場景說明

🚨 實際項目中,數據庫面臨兩類瓶頸:

  • 📌 數據量太大 → 單庫單表撐不住 → 使用 分庫分表 拆解壓力
  • 📌 讀操作壓力太大 → 單庫處理不過來 → 使用 讀寫分離 轉移壓力

? 本項目整合了這兩類方案,構建如下特性系統:

  • 兩個邏輯庫 ds0ds1
  • ds0 搭建一主兩從(主庫:ds0,從庫:ds0_slave1,ds0_slave2)
  • 表按照用戶 ID 分片(user_id % 2)
  • 主寫從讀,輕松實現讀寫分離

🧱 二、架構圖

在這里插入圖片描述

📝 說明:

  • 用戶通過 Controller 發起請求
  • ShardingSphere JDBC 根據操作類型選擇庫、表
  • 如果是寫入操作,走 ds0ds1 的主庫
  • 如果是讀取操作,優先走 ds0_slave1ds0_slave2 從庫,減輕主庫壓力

?? 三、核心配置(application.yml)

🧩 我們通過配置 ShardingSphere 的兩類規則:shardingreadwrite-splitting 實現業務目標。

spring:shardingsphere:datasource:names: ds0, ds1, ds0_slave1, ds0_slave2ds0:type: com.zaxxer.hikari.HikariDataSourcejdbc-url: jdbc:mysql://mysql-master:3307/testdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: rootds0_slave1:type: com.zaxxer.hikari.HikariDataSourcejdbc-url: jdbc:mysql://mysql-slave1:3308/testdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: rootds0_slave2:type: com.zaxxer.hikari.HikariDataSourcejdbc-url: jdbc:mysql://mysql-slave2:3309/testdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: rootds1:type: com.zaxxer.hikari.HikariDataSourcejdbc-url: jdbc:mysql://mysql-master:3306/testdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: root123456rules:sharding:tables:t_user:# 注意:此處使用物理庫名(ds0、ds1)來定義 actual-data-nodesactual-data-nodes: ds$->{0..1}.t_user_$->{0..1}database-strategy:standard:sharding-column: user_idsharding-algorithm-name: database_inlinetable-strategy:standard:sharding-column: user_idsharding-algorithm-name: table_inlinekey-generate-strategy:column: idkey-generator-name: snowflakesharding-algorithms:database_inline:type: INLINEprops:algorithm-expression: ds${user_id % 2}table_inline:type: INLINEprops:algorithm-expression: t_user_${user_id % 2}key-generators:snowflake:type: SNOWFLAKEreadwrite-splitting:data-sources:rw_ds0:static-strategy:write-data-source-name: ds0read-data-source-names: [ds0_slave1,ds0_slave2]load-balancer-name: round_robinrw_ds1:static-strategy:write-data-source-name: ds1read-data-source-names: [ds1]load-balancer-name: round_robinload-balancers:round_robin:type: ROUND_ROBINprops:sql-show: truelogging:level:org.apache.shardingsphere: DEBUG

1. 數據源配置 (datasource)

定義了 4 個 MySQL 數據源(2 個主庫 ds0/ds1 和 2 個從庫 ds0_slave1/ds0_slave2)。

配置項說明
spring.shardingsphere.datasource.names數據源名稱列表:ds0, ds1, ds0_slave1, ds0_slave2
ds0.jdbc-url主庫 ds0 的 JDBC 連接 URL(端口 3307)
ds0.username主庫 ds0 用戶名(root
ds0.password主庫 ds0 密碼(root
ds0_slave1.jdbc-url從庫 ds0_slave1 的 JDBC URL(端口 3308)
ds0_slave2.jdbc-url從庫 ds0_slave2 的 JDBC URL(端口 3309)
ds1.jdbc-url主庫 ds1 的 JDBC URL(端口 3306,與 ds0 不同實例)

2. 分片規則 (sharding)

配置表 t_user 的分片策略和分布式 ID 生成。

分片表配置
配置項作用示例值說明
tables.t_user.actual-data-nodes定義物理節點ds$->{0..1}.t_user_$->{0..1}表達式生成所有物理表,如 ds0.t_user_0ds1.t_user_1
tables.t_user.database-strategy.standard.sharding-column分庫列user_id根據 user_id 計算數據存儲的庫。
tables.t_user.database-strategy.standard.sharding-algorithm-name分庫算法名稱database_inline引用 sharding-algorithms 中定義的算法。
tables.t_user.table-strategy.standard.sharding-column分表列user_id根據 user_id 計算數據存儲的表。
tables.t_user.table-strategy.standard.sharding-algorithm-name分表算法名稱table_inline引用 sharding-algorithms 中定義的算法。
tables.t_user.key-generate-strategy.column主鍵列id指定自動生成主鍵的列。
tables.t_user.key-generate-strategy.key-generator-name主鍵生成器名稱snowflake使用 Snowflake 算法生成分布式 ID。
分片算法
配置項作用示例值說明
sharding-algorithms.database_inline.type算法類型INLINE使用行表達式(Inline)分片算法。
sharding-algorithms.database_inline.props.algorithm-expression分庫表達式ds${user_id % 2}根據 user_id % 2 計算庫索引(0 或 1)。
sharding-algorithms.table_inline.type算法類型INLINE使用行表達式分片算法。
sharding-algorithms.table_inline.props.algorithm-expression分表表達式t_user_${user_id % 2}根據 user_id % 2 計算表索引(0 或 1)。
分布式 ID
配置項作用示例值說明
key-generators.snowflake.type主鍵生成器類型SNOWFLAKE使用 Snowflake 算法生成分布式唯一 ID。

3. 讀寫分離規則 (readwrite-splitting)

配置讀寫分離數據源和負載均衡策略。

數據源 rw_ds0
配置項說明
write-data-source-name寫庫數據源:ds0(主庫)
read-data-source-names讀庫數據源列表:[ds0_slave1, ds0_slave2](兩個從庫)
load-balancer-name負載均衡算法:round_robin(輪詢)
數據源 rw_ds1
配置項說明
write-data-source-name寫庫數據源:ds1(主庫)
read-data-source-names讀庫數據源列表:([ds1]),表示僅使用寫庫讀
load-balancer-name負載均衡算法:round_robin(未實際生效)
負載均衡器
配置項說明
round_robin.type算法類型:ROUND_ROBIN(輪詢調度)

4. 屬性配置 (props)

配置項說明
sql-show: true打印 SQL 日志(便于調試)

配置邏輯總結

spring:shardingsphere:datasource:names: ds0, ds1, ds0_slave1, ds0_slave2
  • 定義三個數據源

    • ds0: 主庫
    • ds0_slave: 從庫(ds0 復制)
    • ds1: 第二個分片主庫
    rules:sharding:tables:t_user:actual-data-nodes: rw_ds$->{0..1}.t_user_$->{0..1}
  • t_user 分片規則:共有 2 庫 x 2 表 結構
            table-strategy:standard:sharding-column: user_idsharding-algorithm-name: user_inline
  • 按照 user_id 做分片(水平拆表)
        sharding-algorithms:user_inline:type: INLINEprops:algorithm-expression: t_user_${user_id % 2}
  • 表名后綴 = user_id % 2,如 t_user_0t_user_1

      readwrite-splitting:data-sources:rw_ds0:static-strategy:write-data-source-name: ds0read-data-source-names: [ds0_slave1,ds0_slave1]
  • 配置 rw_ds0 為讀寫分離庫
  • ds0 負責寫入,ds0_slave1,ds0_slave2 負責讀取
          rw_ds1:static-strategy:write-data-source-name: ds1read-data-source-names: [ds1]
  • ds1 暫無從庫,只支持主庫寫讀

潛在問題

  1. rw_ds1 無讀庫

    • 配置中 rw_ds1.read-data-source-namesds1,可能導致讀請求全部發往主庫 ds1,增加壓力。
  2. 分片與讀寫分離結合

    • 實際數據節點 rw_ds0.t_user_0rw_ds1.t_user_1 的分片邏輯需確保數據均勻分布。

🗃? 四、數據庫建表SQL

db0db1 上執行以下語句,創建兩個分表:

CREATE TABLE t_user_0 (id BIGINT PRIMARY KEY,username VARCHAR(100),user_id INT
);CREATE TABLE t_user_1 LIKE t_user_0;

📌 ds0_slave1, ds0_slave2 是主庫 ds0 的復制庫,MySQL 自動同步,無需手動建表。


👨?💻 五、關鍵代碼

? 項目概覽

sharding-demo/
├── src/
│   ├── main/
│   │   ├── java/com/example/shardingdemo/
│   │   │   ├── controller/
│   │   │   ├── entity/
│   │   │   ├── mapper/
│   │   │   ├── ShardingDemoApplication.java
│   └── resources/
│       ├── application.yml
├── pom.xml

? User 實體類

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {private Long id;private String username;private Integer userId; // 分片鍵
}

? Mapper 接口

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.shardingdemo.entity.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper extends BaseMapper<User> {}

? Controller 控制器

import com.example.shardingdemo.entity.User;
import com.example.shardingdemo.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {private final UserMapper userMapper;@PostMapping("/add")public String addUser(@RequestParam String name, @RequestParam Integer userId) {User user = new User(System.currentTimeMillis(), name, userId);userMapper.insert(user);return "User added.";}@GetMapping("/list")public List<User> selectList() {return userMapper.selectList(null);}@GetMapping("/selectById")public User selectById(Long id){return userMapper.selectById(id);}}

🧪 六、測試驗證

? 添加用戶

http://localhost:8080/user/add?name=Alice&userId=11

控制臺輸出:

Actual SQL: rw_ds1 ::: INSERT INTO t_user_1 ...

? 說明:

  • userId = 11,落到 rw_ds1(ds1)
  • 且表名為 t_user_1,符合 % 2 = 1 的路由邏輯

🧠 七、總結與建議

特性說明
💡 分庫分表擴展寫能力,解決單表瓶頸
💡 讀寫分離減輕主庫壓力,提高系統吞吐
? 可擴展性新增庫或表只需擴展路由規則,無需修改業務代碼
? 高性能多線程批量插入、查詢等場景提升明顯
🔒 安全性通過主從架構,規避讀阻塞或死鎖導致系統不可用

📢 建議配合 Docker + MySQL 主從配置部署驗證,效果最佳。


?? 如果你覺得這篇文章有幫助:

  • 點贊 👍
  • 收藏 ?
  • 留言 💬

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92449.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92449.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92449.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

將普通用戶添加到 Docker 用戶組

這樣可以避免每次使用 Docker 命令時都需要 sudo。以下是具體步驟&#xff1a;1. 創建 Docker 用戶組&#xff08;如果尚未存在&#xff09; 默認情況下&#xff0c;安裝 Docker 時會自動創建 docker 用戶組。可以通過以下命令檢查&#xff1a; groupadd docker&#xff08;如果…

Scrapy(一):輕松爬取圖片網站內容?

目錄 一、CrawlSpider 簡介? 二、實戰案例&#xff1a;圖片網站爬取? 三、代碼解析&#xff1a;核心組件詳解? 類定義&#xff1a; 2.核心屬性&#xff1a;? 3.爬取規則&#xff08;Rules&#xff09;&#xff1a;? 4.數據提取方法&#xff08;parse_item&#xff09;…

使用 systemd 的原生功能來實現 Redis 的自動監控和重啟,而不是依賴額外的腳本最佳實踐方案

使用 systemd 的原生功能來實現 Redis 的自動監控和重啟&#xff0c;而不是依賴額外的腳本最佳實踐方案方案 1&#xff1a;配置 systemd 服務文件&#xff08;推薦&#xff09;1. 檢查/創建 Redis 的 systemd 服務文件2. 配置關鍵參數&#xff08;覆蓋配置示例&#xff09;3. 重…

Eclipse 代碼模板

Eclipse 代碼模板 引言 Eclipse 作為一款功能強大的集成開發環境&#xff08;IDE&#xff09;&#xff0c;深受廣大開發者的喜愛。在編程過程中&#xff0c;使用代碼模板可以大大提高開發效率&#xff0c;減少重復勞動。本文將詳細介紹 Eclipse 代碼模板的配置、使用方法以及一…

輸電線路防外破聲光預警裝置 | 防山火/防釣魚/防施工安全警示系統

在輸電網絡的安全保障中&#xff0c;外力破壞是一個不容忽視的問題&#xff0c;各類隱患可能對電力系統造成嚴重影響。TLKS-PMG-WP 輸電線路聲光防外破警示裝置在應對這類挑戰時&#xff0c;有著獨特的技術表現&#xff0c;下面從功能和技術參數兩方面進行詳細介紹。核心功能解…

STM32——STM32CubeMX

總&#xff1a;STM32——學習總綱 一、簡介 注意&#xff0c;非邏輯代碼。 可兼容不同系列的STM32Cube固件包。 STM32Cube前置知識鏈接&#xff1a; STM32——HAL庫 不可過多依賴&#xff0c;此工具只針對STM32芯片&#xff0c;類似英飛凌芯片無法配置。主要用于參考。 二、安…

Java NIO 核心原理與秋招高頻面試題解析

一、NIO 概述Java NIO&#xff08;New I/O 或 Non-blocking I/O&#xff09;是 Java 1.4 引入的一套全新 I/O API&#xff0c;位于 java.nio 包下。NIO 提供了與傳統 BIO&#xff08;Blocking I/O&#xff09;完全不同的 I/O 處理方式&#xff0c;通過非阻塞模式、緩沖區&#…

vue3+element-plus,el-popover實現篩選彈窗的方法

實現一個篩選框&#xff0c;點擊篩選按鈕出現彈窗&#xff0c;彈窗內有選擇框/輸入框/單選框等等&#xff0c;底部有重置/確定兩個按鈕。需求&#xff1a;點擊篩選外部其他位置可以關閉彈窗&#xff0c;關閉彈窗后已編輯的數據不保存&#xff0c;點擊確定按鈕關閉彈窗&#xff…

python每日一題 貪心算法練習

在一條環路上有 n 個加油站&#xff0c;其中第 i 個加油站有汽油 gas[i] 升。你有一輛油箱容量無限的的汽車&#xff0c;從第 i 個加油站開往第 i1 個加油站需要消耗汽油 cost[i] 升。你從其中的一個加油站出發&#xff0c;開始時油箱為空。給定兩個整數數組 gas 和 cost &…

Python + Pika RabbitMQ集群壓測完整方案

一、最近搭建了個rabbitmq集群 三個磁盤節點&#xff0c;上生產環境之前想做個壓測&#xff0c;測試下穩定性&#xff0c;參考Deepseek做了如下測試方案二、核心代碼實現&#xff1a; 配置文件 (config.py) import os RABBITMQ_NODES [amqp://admin:123456192.168.0.175:8101,…

【第7話:相機模型3】自動駕駛IPM圖像投影拼接技術詳解及代碼示例

IPM圖像投影拼接技術詳解 IPM&#xff08;逆透視映射&#xff09;圖像投影拼接技術是一種在計算機視覺中廣泛應用的圖像處理方法&#xff0c;主要用于將多個透視視圖的圖像轉換為鳥瞰視圖并拼接成一個無縫的大場景圖像。該技術特別適用于自動駕駛、機器人導航和監控系統等領域&…

【測試工程思考】測試自動化基礎能力建設

1 回顧 傳統軟件研發體系下定義的軟件測試是從用戶視角設計的。測試是試圖窮盡用戶行為的工程&#xff0c;從測試用例&#xff08;use case&#xff09;的英文定義就可見一般。測試的邏輯資產就是用自然語言去描述用戶的操作行為或路徑。 但隨著軟件工程向分布式架構和敏捷交付…

進階向:AI聊天機器人(NLP+DeepSeek API)

什么是AI聊天機器人? AI聊天機器人是一種通過自然語言處理(NLP)技術模擬人類對話的智能程序系統。其核心是建立在機器學習算法和大型語言模型基礎上的對話引擎,能夠理解用戶的自然語言輸入,分析語境和意圖,并生成符合上下文的相關回復。 這類機器人系統通常包含以下幾個…

一個C#的段子

猜猜按鈕的結果是啥。 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } public static bool flag true; privat…

使用 gptqmodel 量化 Qwen3-Coder-30B-A3B-Instruct

代碼部分 : quantize_qwen3_coder_30b_a3b_instruct_gptq.py import os########## 環境變量設置 ########## # 當前可用的 CUDA 編號 os.environ["CUDA_VISIBLE_DEVICES"] "1" # GPU 顯存資源片段優化 os.environ["PYTORCH_CUDA_ALLOC_CONF"] …

基于python、django的疫苗接種管理系統

基于python、django的疫苗接種管理系統

Go語言實戰案例:使用sync.Map構建線程安全map

在并發編程中&#xff0c;共享資源的訪問是一個繞不開的問題。Go 中的 map 在并發讀寫時是不安全的&#xff0c;直接使用可能導致程序 panic。因此&#xff0c;在多協程同時訪問 Map 的場景下&#xff0c;必須采取有效的同步措施。本篇將通過一個實戰案例&#xff0c;介紹 Go 的…

關于vue2中對接海康攝像頭以及直播流rtsp或rtmp,后臺ffmpeg轉碼后通過ws實現

最近項目中需要對接攝像頭監控&#xff0c;海康攝像頭為rtsp流格式有一個軟件VLC media player&#xff0c;可以在線進行rtsp或者rtmp流播放&#xff0c;可用來測試流地址是否可用功能實現思路為后臺通過fmpeg把rtsp流進行轉碼&#xff0c;然后通過ws方式進行一幀一幀推送。&am…

Docker容器強制刪除及文件系統修復完整指南

Docker容器強制刪除及文件系統修復完整指南 故障現象與原因分析 ?故障表現?&#xff1a; ERROR: for c9ca40be974d_OpIsosMD_OB unable to remove filesystem unlinkat /data/docker/storage/containers/c9ca40be974d...: structure needs cleaning?根本原因?&#xff1a;…

Matplotlib 知識點總結

1. 基礎繪圖&#xff08;plot函數&#xff09;基本語法&#xff1a;plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)功能特點&#xff1a;可繪制點、線和組合圖形自動生成x軸&#xff08;0-N-1&#xff09;當x未指定時示例&#xff1a;繪制兩點連線、多點不規則線等代碼…