欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL主從復(fù)制數(shù)據(jù)同步的實(shí)現(xiàn)步驟

 更新時(shí)間:2024年12月03日 10:11:07   作者:阿乾之銘  
MySQL主從復(fù)制是一種數(shù)據(jù)同步技術(shù),通過將數(shù)據(jù)從主數(shù)據(jù)庫服務(wù)器復(fù)制到一個(gè)或多個(gè)從數(shù)據(jù)庫服務(wù)器來實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、什么是 MySQL 的主從復(fù)制

MySQL 的主從復(fù)制(Master-Slave Replication)是一種將數(shù)據(jù)從一個(gè)主數(shù)據(jù)庫服務(wù)器(主庫)復(fù)制到一個(gè)或多個(gè)從數(shù)據(jù)庫服務(wù)器(從庫)的技術(shù)。主庫負(fù)責(zé)所有的數(shù)據(jù)寫操作,從庫則通過讀取主庫的二進(jìn)制日志來同步主庫的數(shù)據(jù)變化。主從復(fù)制主要用于實(shí)現(xiàn)數(shù)據(jù)的備份、負(fù)載分擔(dān)和高可用性。

二、具體流程

1. 主庫記錄寫操作

當(dāng)主庫執(zhí)行寫操作(如 INSERTUPDATE 或 DELETE)時(shí),這些操作會(huì)被記錄到二進(jìn)制日志(binlog)中。二進(jìn)制日志保存了所有數(shù)據(jù)更改的歷史記錄,這些記錄將成為從庫同步數(shù)據(jù)的來源。

  • 步驟:主庫將所有寫操作(數(shù)據(jù)變更)記錄到二進(jìn)制日志中。

2. 從庫連接主庫并讀取二進(jìn)制日志

從庫通過一個(gè)稱為IO 線程的進(jìn)程與主庫建立連接,開始讀取主庫的二進(jìn)制日志。主庫會(huì)將日志內(nèi)容發(fā)送給從庫的 IO 線程。

  • 步驟:從庫的 IO 線程連接主庫,持續(xù)接收主庫二進(jìn)制日志的最新內(nèi)容。

3. 從庫將二進(jìn)制日志寫入中繼日志

從庫的 IO 線程將接收到的主庫二進(jìn)制日志復(fù)制到從庫的**中繼日志(relay log)**中。中繼日志在從庫本地保存了一份主庫數(shù)據(jù)變更的副本,供從庫執(zhí)行使用。

  • 步驟:從庫的 IO 線程將接收的日志寫入中繼日志,為數(shù)據(jù)變更做好準(zhǔn)備。

4. 從庫應(yīng)用中繼日志,執(zhí)行數(shù)據(jù)同步

從庫的另一個(gè)線程(稱為SQL 線程)負(fù)責(zé)讀取中繼日志中的內(nèi)容,并逐條在從庫上執(zhí)行,以實(shí)現(xiàn)數(shù)據(jù)的同步。每當(dāng)主庫有新的數(shù)據(jù)變更,從庫都會(huì)從中繼日志中獲取并執(zhí)行這些變更,從而保持與主庫的數(shù)據(jù)一致。

  • 步驟:從庫的 SQL 線程從中繼日志中讀取并執(zhí)行記錄的操作,逐步更新從庫數(shù)據(jù)。

5. 持續(xù)復(fù)制和同步

整個(gè)主從復(fù)制過程是一個(gè)持續(xù)的流程,只要主庫有新的數(shù)據(jù)變更,從庫就會(huì)自動(dòng)獲取并執(zhí)行對(duì)應(yīng)的更改,從而保持與主庫數(shù)據(jù)的一致性。主從復(fù)制會(huì)持續(xù)保持同步,以確保從庫能夠?qū)崟r(shí)或接近實(shí)時(shí)地反映主庫的最新數(shù)據(jù)。

  • 步驟:主庫的所有寫操作都會(huì)記錄到日志中,實(shí)時(shí)同步到從庫;從庫持續(xù)讀取并執(zhí)行日志內(nèi)容,更新自身數(shù)據(jù)。

三、作用和好處

  • 讀寫分離,提高性能

    • 減輕主庫壓力:將大量的讀操作分散到從庫,主庫主要負(fù)責(zé)寫操作,大大降低了主庫的負(fù)載壓力。
    • 提升并發(fā)處理能力:增加從庫的數(shù)量可以提升系統(tǒng)的讀并發(fā)能力,處理更多用戶的并發(fā)請(qǐng)求,提升系統(tǒng)整體性能。
  • 高可用性和容錯(cuò)性

    • 數(shù)據(jù)冗余與容災(zāi):主從復(fù)制提供了數(shù)據(jù)的實(shí)時(shí)備份,從庫可以在主庫發(fā)生故障時(shí)快速接管服務(wù),提高系統(tǒng)的可用性。
    • 故障切換:當(dāng)主庫出現(xiàn)故障時(shí),可以臨時(shí)將從庫升級(jí)為主庫,保障服務(wù)持續(xù)運(yùn)行。
  • 負(fù)載均衡

    • 分擔(dān)查詢壓力:多個(gè)從庫可以共同承擔(dān)讀取請(qǐng)求,通過負(fù)載均衡算法(如輪詢、隨機(jī)等)分配請(qǐng)求,提升系統(tǒng)的穩(wěn)定性。
    • 避免單點(diǎn)瓶頸:讀操作分散到不同的從庫上執(zhí)行,避免了單一數(shù)據(jù)庫因訪問量過大而成為系統(tǒng)瓶頸。
  • 擴(kuò)展性

    • 水平擴(kuò)展:根據(jù)業(yè)務(wù)增長,靈活增加從庫數(shù)量,滿足性能需求,而無需對(duì)主庫進(jìn)行大幅度改造。
    • 彈性擴(kuò)展:可以根據(jù)實(shí)際流量,增加或減少從庫,做到靈活應(yīng)對(duì)負(fù)載變化。
  • 數(shù)據(jù)備份和安全性

    • 數(shù)據(jù)保護(hù):從庫可以用于數(shù)據(jù)備份和容災(zāi),防止主庫故障導(dǎo)致的數(shù)據(jù)丟失。
    • 快速恢復(fù):在數(shù)據(jù)意外丟失或損壞時(shí),可以通過從庫恢復(fù)主庫的數(shù)據(jù)。

四、在實(shí)際應(yīng)用中的場(chǎng)景與示例

1. 電商平臺(tái)

在電商平臺(tái)中,用戶的瀏覽和查詢操作會(huì)產(chǎn)生大量的讀請(qǐng)求,而訂單創(chuàng)建、支付等操作會(huì)產(chǎn)生寫請(qǐng)求。通過主從復(fù)制的讀寫分離:

  • 查詢庫存、商品詳情等高頻率的讀操作可以由從庫承擔(dān),減輕主庫壓力。
  • 用戶下單、支付等寫操作由主庫負(fù)責(zé),確保數(shù)據(jù)的完整性和一致性。

2. 社交媒體或內(nèi)容網(wǎng)站

在社交媒體應(yīng)用中,大量的內(nèi)容瀏覽和搜索會(huì)產(chǎn)生大量的讀操作,而發(fā)布、點(diǎn)贊等則是寫操作。通過主從復(fù)制,平臺(tái)可以:

  • 使用從庫來承擔(dān)瀏覽、查詢等操作,確保高并發(fā)下的快速響應(yīng)。
  • 將寫操作指向主庫,確保用戶發(fā)布或點(diǎn)贊的實(shí)時(shí)更新。

五、在 Spring Boot 項(xiàng)目中集成 MySQL 主從復(fù)制

在 Spring Boot 項(xiàng)目中集成 MySQL 的主從復(fù)制數(shù)據(jù)同步,指的是將 Spring Boot 應(yīng)用程序連接到配置有主從復(fù)制的 MySQL 數(shù)據(jù)庫系統(tǒng)上,完成主從數(shù)據(jù)庫的配置管理,實(shí)現(xiàn)自動(dòng)的讀寫分離。具體來說,就是通過多數(shù)據(jù)源配置,讓 Spring Boot 自動(dòng)識(shí)別是寫請(qǐng)求還是讀請(qǐng)求,并將寫請(qǐng)求發(fā)送到主庫,讀請(qǐng)求發(fā)送到從庫。

集成的關(guān)鍵要素:

  • 多數(shù)據(jù)源配置:在 Spring Boot 中配置主數(shù)據(jù)庫和從數(shù)據(jù)庫的連接。
  • 動(dòng)態(tài)數(shù)據(jù)源路由:在應(yīng)用層面實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)選擇,讀操作使用從庫,寫操作使用主庫。
  • 讀寫分離注解或切面:利用自定義注解或 AOP 切面控制數(shù)據(jù)源的切換。

1.配置 MySQL 的主從復(fù)制環(huán)境

配置 MySQL 的主從復(fù)制環(huán)境是實(shí)現(xiàn) MySQL 主從復(fù)制數(shù)據(jù)同步的第一步。主要步驟包括設(shè)置主庫(Master)和從庫(Slave),并驗(yàn)證主從復(fù)制的成功。

1.1 設(shè)置主庫(Master)

配置主庫是主從復(fù)制的第一步。主庫負(fù)責(zé)記錄數(shù)據(jù)變更并將其傳遞給從庫。

1.1.1 修改主庫的配置文件

在主庫的 MySQL 配置文件中(通常位于 /etc/my.cnf 或 /etc/mysql/my.cnf),需要啟用二進(jìn)制日志并為主庫設(shè)置一個(gè)唯一的 server-id。在 [mysqld] 部分添加如下配置:

[mysqld]
server-id=1                 # 主庫的唯一 ID
log-bin=mysql-bin           # 啟用二進(jìn)制日志,主從復(fù)制依賴于此
binlog-do-db=your_database  # 需要同步的數(shù)據(jù)庫名稱,多個(gè)數(shù)據(jù)庫可添加多行
  • server-id:用于標(biāo)識(shí)每個(gè) MySQL 實(shí)例的唯一標(biāo)識(shí)符,主庫的 server-id 一般設(shè)置為 1。
  • log-bin:啟用二進(jìn)制日志,這是主從復(fù)制的基礎(chǔ)。
  • binlog-do-db:指定需要同步的數(shù)據(jù)庫(多個(gè)數(shù)據(jù)庫可以多行設(shè)置)。

注意:如果需要同步多個(gè)數(shù)據(jù)庫,可以多次添加 binlog-do-db 行,例如:

binlog-do-db=database1
binlog-do-db=database2

1.1.2 重啟 MySQL 服務(wù)

修改配置文件后,需要重啟 MySQL 以使配置生效:

# Linux 系統(tǒng)
sudo systemctl restart mysqld

# Windows 系統(tǒng)
net stop mysql
net start mysql

1.1.3 創(chuàng)建用于復(fù)制的用戶

在主庫中創(chuàng)建一個(gè)用于復(fù)制的用戶,并授予 REPLICATION SLAVE 權(quán)限。這個(gè)用戶用于從庫連接主庫并進(jìn)行數(shù)據(jù)同步。

在主庫的 MySQL 命令行中執(zhí)行以下命令:

CREATE USER 'replica_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'replica_user'@'%';
FLUSH PRIVILEGES;
  • replica_user:用于復(fù)制的用戶名,可以自定義。
  • password:復(fù)制用戶的密碼,注意使用強(qiáng)密碼。
  • %:允許所有遠(yuǎn)程 IP 訪問。如果只允許特定從庫連接,可以用從庫的 IP 地址代替 %。

1.1.4 獲取主庫的二進(jìn)制日志信息

為了讓從庫知道從何處開始復(fù)制數(shù)據(jù),主庫需要提供當(dāng)前的二進(jìn)制日志位置??梢酝ㄟ^以下命令查看:

SHOW MASTER STATUS;

命令執(zhí)行后,會(huì)輸出如下內(nèi)容:

+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      154 | your_database|                  |
+------------------+----------+--------------+------------------+
  • File:當(dāng)前的二進(jìn)制日志文件名。
  • Position:二進(jìn)制日志的偏移量,從該位置開始讀取數(shù)據(jù)。

建議:在生產(chǎn)環(huán)境中,執(zhí)行 SHOW MASTER STATUS; 之前,可以先執(zhí)行 FLUSH TABLES WITH READ LOCK; 來鎖定表,防止數(shù)據(jù)寫入導(dǎo)致的數(shù)據(jù)不一致。獲取信息后再執(zhí)行 UNLOCK TABLES; 解鎖。

1.2 設(shè)置從庫(Slave)

配置從庫是主從復(fù)制的第二步。配置從庫連接到主庫并開始同步數(shù)據(jù)。

1.2.1 修改從庫的配置文件

在從庫的 MySQL 配置文件中(通常是 /etc/my.cnf 或 /etc/mysql/my.cnf),設(shè)置一個(gè)唯一的 server-id 并配置中繼日志和只讀模式。 在 [mysqld] 部分添加以下配置:

[mysqld]
server-id=2                 # 從庫的唯一 ID,不能與主庫或其他從庫相同
relay-log=relay-log         # 設(shè)置中繼日志文件名前綴
read-only=1                 # 設(shè)置只讀模式,防止誤操作
  • server-id:從庫的唯一標(biāo)識(shí)符,每個(gè)從庫的 server-id 也需要是唯一的,通常從 2 開始。
  • relay-log:指定中繼日志的前綴,用于存儲(chǔ)從主庫同步的數(shù)據(jù)。
  • read-only:開啟只讀模式,防止意外寫入。此模式下,擁有 SUPER 權(quán)限的用戶仍可以寫入數(shù)據(jù)。

1.2.2 重啟 MySQL 服務(wù)

修改配置文件后,重啟從庫的 MySQL 服務(wù)以應(yīng)用配置:

# Linux 系統(tǒng)
sudo systemctl restart mysqld

# Windows 系統(tǒng)
net stop mysql
net start mysql

1.2.3 配置從庫連接到主庫

在從庫的 MySQL 中,配置主庫信息以便開始復(fù)制。需要用到在主庫上記錄的 File 和 Position 值。

CHANGE MASTER TO
    MASTER_HOST='主庫的 IP 地址',
    MASTER_USER='replica_user',
    MASTER_PASSWORD='password',
    MASTER_LOG_FILE='mysql-bin.000001',  -- 主庫的 File 值
    MASTER_LOG_POS=154;                  -- 主庫的 Position 值
  • MASTER_HOST:主庫的 IP 地址。
  • MASTER_USER:在主庫上創(chuàng)建的用于復(fù)制的用戶(如 replica_user)。
  • MASTER_PASSWORD:復(fù)制用戶的密碼。
  • MASTER_LOG_FILE:主庫的二進(jìn)制日志文件名。
  • MASTER_LOG_POS:二進(jìn)制日志的位置偏移量。

1.2.4 啟動(dòng)復(fù)制進(jìn)程

配置完成后,啟動(dòng)從庫的復(fù)制進(jìn)程以開始從主庫復(fù)制數(shù)據(jù):

START SLAVE;

1.2.5 查看從庫的復(fù)制狀態(tài)

運(yùn)行以下命令檢查從庫的狀態(tài),確認(rèn)從庫已成功連接到主庫并開始復(fù)制數(shù)據(jù):

SHOW SLAVE STATUS\G
  • Slave_IO_Running:應(yīng)為 Yes,表示從庫的 IO 線程正在讀取主庫的日志。
  • Slave_SQL_Running:應(yīng)為 Yes,表示從庫的 SQL 線程正在執(zhí)行主庫傳遞的日志。
  • Last_IO_Error 和 Last_SQL_Error:如果存在錯(cuò)誤信息,會(huì)在此處顯示。

如果 Slave_IO_Running 或 Slave_SQL_Running 為 No,請(qǐng)查看 Last_IO_Error 或 Last_SQL_Error 中的錯(cuò)誤消息,并根據(jù)錯(cuò)誤提示排查問題。

1.3 驗(yàn)證主從復(fù)制是否成功

在配置完成后,驗(yàn)證主從復(fù)制的成功性。確保主庫的寫操作能夠被從庫正確同步。

1.3.1 在主庫上創(chuàng)建測(cè)試數(shù)據(jù)

在主庫上選擇用于復(fù)制的數(shù)據(jù)庫,并創(chuàng)建一個(gè)測(cè)試表插入數(shù)據(jù):

USE your_database;
CREATE TABLE test_table (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

INSERT INTO test_table (id, name) VALUES (1, 'Test Data');

1.3.2 在從庫上檢查數(shù)據(jù)同步情況

在從庫上選擇相同的數(shù)據(jù)庫,查詢 test_table 表,確認(rèn)是否同步了主庫的數(shù)據(jù):

USE your_database;
SELECT * FROM test_table;
  • 如果可以看到 Test Data,則表示主從復(fù)制配置成功并且工作正常。

1.3.3 驗(yàn)證實(shí)時(shí)同步效果

在主庫上繼續(xù)插入或更新數(shù)據(jù),再次在從庫上查詢,驗(yàn)證數(shù)據(jù)是否能夠及時(shí)同步。主從復(fù)制一般情況下會(huì)立即同步,延遲較小。

1.4 故障排查

在配置主從復(fù)制的過程中,可能會(huì)遇到以下常見問題:

1 從庫無法連接到主庫

  • 檢查網(wǎng)絡(luò)連接:確保主庫的防火墻允許從庫的 IP 地址訪問 MySQL 的 3306 端口。

2 權(quán)限問題

  • 用戶權(quán)限:確保在主庫上創(chuàng)建的用戶擁有 REPLICATION SLAVE 權(quán)限。

3 主從版本兼容性問題

  • 版本兼容性:確保主庫和從庫的 MySQL 版本相互兼容,推薦使用相同的版本。

4 日志位置不正確

  • 文件和位置錯(cuò)誤:如果配置的 File 和 Position 不正確,可以重新設(shè)置主從復(fù)制位置。

2.在 Spring Boot 項(xiàng)目中配置多數(shù)據(jù)源

配置多數(shù)據(jù)源是實(shí)現(xiàn)主從復(fù)制的重要步驟。通過多數(shù)據(jù)源配置,Spring Boot 應(yīng)用可以自動(dòng)區(qū)分并選擇主庫或從庫,從而實(shí)現(xiàn)讀寫分離。這一步的具體操作包括添加依賴、配置數(shù)據(jù)源信息,以及配置數(shù)據(jù)源路由以實(shí)現(xiàn)自動(dòng)選擇主庫或從庫。以下是詳細(xì)的分步講解。

2.1 添加必要的依賴

在使用 Spring Data JPA 和 MySQL 多數(shù)據(jù)源時(shí),需要添加以下依賴項(xiàng):

  • MySQL 驅(qū)動(dòng):支持連接 MySQL 數(shù)據(jù)庫。
  • Spring Data JPA:提供 JPA 支持,簡化數(shù)據(jù)庫操作。
  • HikariCP 連接池:Spring Boot 默認(rèn)的連接池,適合高并發(fā)環(huán)境且支持多數(shù)據(jù)源配置。

在項(xiàng)目的 pom.xml 中添加以下依賴:

<dependencies>
    <!-- MySQL 驅(qū)動(dòng) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!-- Spring Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- HikariCP 連接池(Spring Boot 默認(rèn)連接池) -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
    </dependency>
</dependencies>

2.2 在配置文件中定義主庫和從庫的數(shù)據(jù)源信息

接下來,需要在 application.properties 中定義主庫和從庫的連接信息。主庫通常用于寫操作,從庫用于讀操作。

application.properties 文件內(nèi)容

# 主庫配置
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.master.url=jdbc:mysql://主庫IP地址:3306/your_database?useSSL=false&characterEncoding=utf8
spring.datasource.master.username=主庫用戶名
spring.datasource.master.password=主庫密碼

# 從庫配置
spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.slave.url=jdbc:mysql://從庫IP地址:3306/your_database?useSSL=false&characterEncoding=utf8
spring.datasource.slave.username=從庫用戶名
spring.datasource.slave.password=從庫密碼

說明

  • spring.datasource.master:主庫連接信息,用于寫操作。
  • spring.datasource.slave:從庫連接信息,用于讀操作。
  • driver-class-name:MySQL 驅(qū)動(dòng)類名。
  • url:數(shù)據(jù)庫連接 URL,其中包含數(shù)據(jù)庫的 IP 地址和數(shù)據(jù)庫名稱。
  • username 和 password:數(shù)據(jù)庫的用戶名和密碼。

2.3 創(chuàng)建數(shù)據(jù)源配置類,配置主從數(shù)據(jù)源

在項(xiàng)目中添加一個(gè)配置類,用于定義主庫和從庫數(shù)據(jù)源,并通過一個(gè)動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)自動(dòng)選擇主庫或從庫。

2.3.1 配置主庫和從庫的數(shù)據(jù)源

首先,我們需要在配置類中定義兩個(gè)數(shù)據(jù)源,即主庫和從庫。主庫主要用于寫操作,從庫用于讀操作。

package com.example.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import org.springframework.boot.jdbc.DataSourceBuilder;

@Configuration
public class DataSourceConfig {

    // 定義主庫數(shù)據(jù)源
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 定義從庫數(shù)據(jù)源
    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }
}

說明

  • @ConfigurationProperties:這個(gè)注解將 application.properties 中 spring.datasource.master 和 spring.datasource.slave 配置的信息綁定到 masterDataSource 和 slaveDataSource 上。這樣,Spring Boot 會(huì)自動(dòng)讀取配置文件中的主從庫信息,并將它們分別注入到兩個(gè)數(shù)據(jù)源對(duì)象中。

  • DataSourceBuilder:這是 Spring 提供的一個(gè)工具類,通過它可以根據(jù)配置文件構(gòu)建 DataSource 對(duì)象。DataSource 是與數(shù)據(jù)庫連接的核心組件,主要用于管理數(shù)據(jù)庫連接、連接池等信息。

2.3.2 動(dòng)態(tài)數(shù)據(jù)源路由

為了實(shí)現(xiàn)主從分離,我們需要根據(jù)請(qǐng)求自動(dòng)選擇主庫或從庫的數(shù)據(jù)源。AbstractRoutingDataSource 是 Spring 提供的一個(gè)抽象類,可以根據(jù)用戶定義的路由規(guī)則動(dòng)態(tài)選擇數(shù)據(jù)源。

創(chuàng)建 DynamicDataSource 類:該類繼承自 AbstractRoutingDataSource,通過設(shè)置鍵值映射來實(shí)現(xiàn)數(shù)據(jù)源選擇。

package com.example.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    // 設(shè)置當(dāng)前線程的數(shù)據(jù)源(主庫或從庫)
    public static void setDataSource(String dataSourceKey) {
        contextHolder.set(dataSourceKey);
    }

    // 清除當(dāng)前線程的數(shù)據(jù)源
    public static void clearDataSource() {
        contextHolder.remove();
    }

    // 確定當(dāng)前數(shù)據(jù)源(由 AbstractRoutingDataSource 調(diào)用)
    @Override
    protected Object determineCurrentLookupKey() {
        return contextHolder.get();
    }
}

代碼詳解

  • contextHolder:使用 ThreadLocal 存儲(chǔ)當(dāng)前線程的數(shù)據(jù)源標(biāo)識(shí)(master 或 slave)。ThreadLocal 確保每個(gè)線程擁有獨(dú)立的變量副本,不會(huì)干擾其他線程。

  • setDataSource:用于設(shè)置當(dāng)前線程的數(shù)據(jù)源,通過傳入 master 或 slave 來指定主庫或從庫。

  • clearDataSource:用于清除當(dāng)前線程的數(shù)據(jù)源,避免數(shù)據(jù)源信息在線程之間混淆。

  • determineCurrentLookupKey:這是 AbstractRoutingDataSource 提供的方法,它會(huì)在每次數(shù)據(jù)庫操作時(shí)調(diào)用。根據(jù) contextHolder 中的數(shù)據(jù)源標(biāo)識(shí),選擇主庫或從庫。

2.3.3 將主從數(shù)據(jù)源注入到動(dòng)態(tài)數(shù)據(jù)源

我們需要將主庫和從庫的數(shù)據(jù)源注入到動(dòng)態(tài)數(shù)據(jù)源中,并根據(jù)不同的業(yè)務(wù)需求自動(dòng)選擇。

@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource(
        @Qualifier("masterDataSource") DataSource masterDataSource,
        @Qualifier("slaveDataSource") DataSource slaveDataSource) {

    Map<Object, Object> targetDataSources = new HashMap<>();
    targetDataSources.put("master", masterDataSource);
    targetDataSources.put("slave", slaveDataSource);

    DynamicDataSource dynamicDataSource = new DynamicDataSource();
    dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 設(shè)置默認(rèn)的數(shù)據(jù)源
    dynamicDataSource.setTargetDataSources(targetDataSources);      // 將主庫和從庫的數(shù)據(jù)源加入路由

    return dynamicDataSource;
}

代碼詳解

  • @Qualifier:指定 masterDataSource 和 slaveDataSource,通過依賴注入的方式將主庫和從庫的數(shù)據(jù)源傳入 dynamicDataSource

  • targetDataSources:將 master 和 slave 作為鍵,分別映射到 masterDataSource 和 slaveDataSourceDynamicDataSource 會(huì)通過 determineCurrentLookupKey 方法自動(dòng)選擇對(duì)應(yīng)的數(shù)據(jù)源。

  • setDefaultTargetDataSource:設(shè)置默認(rèn)的數(shù)據(jù)源。在沒有指定數(shù)據(jù)源的情況下,系統(tǒng)會(huì)使用默認(rèn)數(shù)據(jù)源(一般為主庫)。

2.3.4 配置 EntityManagerFactory 使用動(dòng)態(tài)數(shù)據(jù)源

對(duì)于使用 JPA 的項(xiàng)目,EntityManagerFactory 是 JPA 的核心組件之一。它負(fù)責(zé)管理實(shí)體管理器,處理 JPA 的持久化操作。這里需要將 EntityManagerFactory 配置為使用動(dòng)態(tài)數(shù)據(jù)源,以實(shí)現(xiàn)主從分離。

@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
        @Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dynamicDataSource); // 使用動(dòng)態(tài)數(shù)據(jù)源
    em.setPackagesToScan("com.example.entity"); // 實(shí)體類包名
    em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); // 設(shè)置 JPA 供應(yīng)商為 Hibernate
    return em;
}

代碼詳解

  • setDataSource:設(shè)置 JPA 的數(shù)據(jù)源為 dynamicDataSource,這樣 JPA 會(huì)根據(jù)動(dòng)態(tài)數(shù)據(jù)源的路由選擇合適的數(shù)據(jù)源。

  • setPackagesToScan:指定 JPA 實(shí)體類所在的包路徑,JPA 會(huì)掃描該包中的實(shí)體類,進(jìn)行數(shù)據(jù)庫操作的映射。

  • HibernateJpaVendorAdapter:設(shè)置 JPA 的供應(yīng)商適配器。這里我們使用 Hibernate 作為 JPA 的實(shí)現(xiàn),它提供了 Hibernate 特有的優(yōu)化和配置支持。

通過配置 EntityManagerFactory 使用 dynamicDataSource,我們可以讓 JPA 在操作數(shù)據(jù)庫時(shí)自動(dòng)根據(jù)業(yè)務(wù)需要切換到主庫或從庫,從而實(shí)現(xiàn)主從分離和讀寫分離。

2.3.5 配置事務(wù)管理器

Spring Data JPA 默認(rèn)需要一個(gè)事務(wù)管理器來管理事務(wù)。我們需要為動(dòng)態(tài)數(shù)據(jù)源配置一個(gè) JpaTransactionManager,以確保事務(wù)操作可以正確地應(yīng)用于當(dāng)前選擇的數(shù)據(jù)源(主庫或從庫)。

@Bean(name = "transactionManager")
public JpaTransactionManager transactionManager(
        @Qualifier("entityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactory) {
    return new JpaTransactionManager(entityManagerFactory.getObject());
}

代碼詳解

  • JpaTransactionManager:Spring 提供的 JPA 事務(wù)管理器,它會(huì)自動(dòng)處理 EntityManager 的創(chuàng)建和關(guān)閉,并確保在事務(wù)中對(duì)數(shù)據(jù)庫操作的 ACID 特性(原子性、一致性、隔離性、持久性)。

  • entityManagerFactory.getObject():將 entityManagerFactory(配置了動(dòng)態(tài)數(shù)據(jù)源的實(shí)體管理器工廠)傳遞給 JpaTransactionManager。這樣,事務(wù)管理器會(huì)根據(jù)動(dòng)態(tài)數(shù)據(jù)源路由來管理事務(wù),確保事務(wù)一致性。

3.實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)切換

為了實(shí)現(xiàn)數(shù)據(jù)庫的主從切換,使得 Spring Boot 項(xiàng)目可以根據(jù)操作類型自動(dòng)選擇主庫或從庫,我們需要實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)切換。實(shí)現(xiàn)動(dòng)態(tài)切換的關(guān)鍵步驟包括:定義自定義注解、創(chuàng)建 AOP 切面,在方法執(zhí)行時(shí)動(dòng)態(tài)地決定使用哪個(gè)數(shù)據(jù)源。

3.1 創(chuàng)建 @DataSource 注解(用于標(biāo)識(shí)使用哪個(gè)數(shù)據(jù)源)

首先,我們創(chuàng)建一個(gè)自定義注解 @DataSource,用于標(biāo)識(shí)在特定方法或類上指定的數(shù)據(jù)源類型(如主庫 master 或從庫 slave)。有了這個(gè)注解之后,我們可以在代碼中靈活地指定哪些操作使用主庫,哪些操作使用從庫。

package com.example.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE}) // 可以用在方法或類上
@Retention(RetentionPolicy.RUNTIME)             // 在運(yùn)行時(shí)保留,便于通過反射獲取
@Documented
public @interface DataSource {
    String value() default "master"; // 默認(rèn)使用主庫
}

注解參數(shù)說明

  • @Target:定義注解的使用位置,ElementType.METHOD 表示可以作用于方法,ElementType.TYPE 表示可以作用于類。

  • @Retention:指定注解的保留策略為 RUNTIME,即該注解會(huì)保留到運(yùn)行時(shí),并且可以通過反射獲取,這樣切面類可以在運(yùn)行時(shí)識(shí)別注解。

  • value:注解的屬性,用來指定數(shù)據(jù)源類型,默認(rèn)為 "master",表示主庫。我們可以在使用注解時(shí),通過設(shè)置 @DataSource("slave") 來指定從庫。

3.2 創(chuàng)建 DataSourceAspect 切面類(根據(jù)注解動(dòng)態(tài)切換數(shù)據(jù)源)

AOP(面向切面編程)可以在方法調(diào)用前后動(dòng)態(tài)地切入代碼邏輯。在這里,我們編寫一個(gè) AOP 切面,用于在方法調(diào)用之前,根據(jù) @DataSource 注解的值設(shè)置數(shù)據(jù)源。在方法調(diào)用之后,清除數(shù)據(jù)源的標(biāo)識(shí),以確保不會(huì)影響后續(xù)操作。

package com.example.aspect;

import com.example.annotation.DataSource;
import com.example.config.DynamicDataSource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceAspect {

    // 定義切點(diǎn):匹配帶有 @DataSource 注解的方法或類
    @Pointcut("@annotation(com.example.annotation.DataSource) || @within(com.example.annotation.DataSource)")
    public void dataSourcePointCut() {
    }

    // 在方法執(zhí)行前,根據(jù)注解的值切換數(shù)據(jù)源
    @Before("dataSourcePointCut()")
    public void before(JoinPoint point) {
        String dataSource = "master"; // 默認(rèn)使用主庫
        Class<?> targetClass = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        
        // 獲取方法上的 @DataSource 注解
        DataSource ds = signature.getMethod().getAnnotation(DataSource.class);
        if (ds != null) {
            dataSource = ds.value();
        } else if (targetClass.isAnnotationPresent(DataSource.class)) {
            // 如果方法上沒有注解,則讀取類上的 @DataSource 注解
            ds = targetClass.getAnnotation(DataSource.class);
            if (ds != null) {
                dataSource = ds.value();
            }
        }

        // 設(shè)置當(dāng)前線程的數(shù)據(jù)源標(biāo)識(shí)
        DynamicDataSource.setDataSource(dataSource);
    }

    // 在方法執(zhí)行后,清除數(shù)據(jù)源標(biāo)識(shí)
    @After("dataSourcePointCut()")
    public void after(JoinPoint point) {
        DynamicDataSource.clearDataSource();
    }
}

切面類代碼詳解

  • @Pointcut:定義切點(diǎn) dataSourcePointCut,用于匹配所有帶有 @DataSource 注解的方法或類。這意味著我們可以在方法上、類上使用 @DataSource 來控制數(shù)據(jù)源選擇。

  • @Before:在目標(biāo)方法執(zhí)行之前觸發(fā) before 方法。

    • MethodSignature:通過 MethodSignature 可以獲取方法的注解。

    • dataSource:默認(rèn)值為 "master"(主庫)。首先檢查方法上的 @DataSource 注解,如果沒有找到,再檢查類上的 @DataSource 注解。

    • DynamicDataSource.setDataSource(dataSource):根據(jù)注解值設(shè)置當(dāng)前線程使用的數(shù)據(jù)源(主庫或從庫)。這使得后續(xù)的數(shù)據(jù)庫操作將根據(jù)注解指定的數(shù)據(jù)源執(zhí)行。

  • @After:在目標(biāo)方法執(zhí)行后觸發(fā) after 方法,用于清除當(dāng)前線程的數(shù)據(jù)源標(biāo)識(shí),以避免線程復(fù)用時(shí)對(duì)其他請(qǐng)求產(chǎn)生干擾。DynamicDataSource.clearDataSource() 方法會(huì)移除當(dāng)前線程的數(shù)據(jù)源標(biāo)識(shí)。

4.在業(yè)務(wù)代碼中使用

4.1 使用 @DataSource 注解

在業(yè)務(wù)代碼中,可以在需要使用主庫或從庫的業(yè)務(wù)方法上添加 @DataSource 注解。默認(rèn)情況下,@DataSource 注解的 value 屬性是 "master",表示主庫。我們可以在查詢類方法上標(biāo)記 @DataSource("slave") 以使用從庫,從而實(shí)現(xiàn)讀寫分離。

4.1.1.在服務(wù)層使用 @DataSource 注解

假設(shè)我們有一個(gè) UserService 服務(wù)類,該類提供了查詢用戶列表和保存用戶的功能。我們可以通過 @DataSource 注解指定使用的數(shù)據(jù)庫。

import com.example.annotation.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // 使用從庫(slave)進(jìn)行讀取操作
    @DataSource("slave")
    public List<User> getUsers() {
        // 數(shù)據(jù)庫查詢操作,這里會(huì)通過切面選擇從庫
        return userRepository.findAll();
    }

    // 使用主庫(master)進(jìn)行寫入操作
    @DataSource("master")
    public void saveUser(User user) {
        // 數(shù)據(jù)庫寫入操作,這里會(huì)通過切面選擇主庫
        userRepository.save(user);
    }
}

示例說明

  • getUsers 方法:由于標(biāo)注了 @DataSource("slave") 注解,因此在執(zhí)行 getUsers 方法時(shí)會(huì)選擇從庫作為當(dāng)前數(shù)據(jù)源,從而使查詢操作通過從庫完成,減輕主庫壓力。

  • saveUser 方法:標(biāo)注了 @DataSource("master") 注解,因此在執(zhí)行 saveUser 方法時(shí)會(huì)選擇主庫作為當(dāng)前數(shù)據(jù)源,從而保證數(shù)據(jù)寫入操作在主庫上進(jìn)行,確保數(shù)據(jù)的一致性。

4.1.2.在 DAO 層(數(shù)據(jù)持久層)使用 @DataSource 注解

假設(shè)我們將數(shù)據(jù)源控制進(jìn)一步細(xì)化到 DAO 層。例如,在 UserRepository 中的查詢和保存方法上分別指定數(shù)據(jù)源。

import com.example.annotation.DataSource;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    // 使用從庫(slave)進(jìn)行讀取操作
    @DataSource("slave")
    List<User> findByName(String name);

    // 使用主庫(master)進(jìn)行寫入操作
    @DataSource("master")
    User save(User user);
}

示例說明

  • findByName 方法:該方法標(biāo)注了 @DataSource("slave"),因此在調(diào)用 findByName 時(shí),數(shù)據(jù)查詢操作將通過從庫完成。

  • save 方法:該方法標(biāo)注了 @DataSource("master"),確保數(shù)據(jù)寫入操作始終通過主庫進(jìn)行,保證了數(shù)據(jù)的完整性。

注意:將 @DataSource 注解放在服務(wù)層和 DAO 層都會(huì)生效。實(shí)際應(yīng)用中可以根據(jù)業(yè)務(wù)邏輯的復(fù)雜程度來決定在哪一層實(shí)現(xiàn)數(shù)據(jù)源的切換。

4.2 確保讀操作走從庫,寫操作走主庫

通過在業(yè)務(wù)方法中使用 @DataSource 注解,可以實(shí)現(xiàn)以下的邏輯:

1.讀操作走從庫:在查詢數(shù)據(jù)的方法上添加 @DataSource("slave"),使這些方法通過從庫執(zhí)行。

  • 從庫通常用于處理讀操作。這樣可以分擔(dān)主庫的負(fù)載,提升系統(tǒng)的讀取性能。
  • 因?yàn)閺膸斓臄?shù)據(jù)來自主庫的復(fù)制,存在一定延遲,所以一般不用于強(qiáng)一致性要求的場(chǎng)景,而適合對(duì)實(shí)時(shí)性要求較低的查詢場(chǎng)景。

2.寫操作走主庫:在插入、更新、刪除數(shù)據(jù)的方法上添加 @DataSource("master"),確保這些操作通過主庫執(zhí)行。

  • 主庫是數(shù)據(jù)的源頭,負(fù)責(zé)處理寫入、更新等操作,以確保數(shù)據(jù)的準(zhǔn)確性和一致性。
  • 這樣可以避免因?yàn)閺?fù)制延遲導(dǎo)致的數(shù)據(jù)不一致問題。

示例:在 ProductService 中實(shí)現(xiàn)讀寫分離

import com.example.annotation.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    // 使用從庫讀取產(chǎn)品列表
    @DataSource("slave")
    public List<Product> getAllProducts() {
        // 從庫執(zhí)行查詢
        return productRepository.findAll();
    }

    // 使用主庫保存產(chǎn)品信息
    @DataSource("master")
    public void addProduct(Product product) {
        // 主庫執(zhí)行插入操作
        productRepository.save(product);
    }

    // 更新產(chǎn)品信息,使用主庫
    @DataSource("master")
    public void updateProduct(Product product) {
        // 主庫執(zhí)行更新操作
        productRepository.save(product);
    }

    // 刪除產(chǎn)品信息,使用主庫
    @DataSource("master")
    public void deleteProductById(Long productId) {
        // 主庫執(zhí)行刪除操作
        productRepository.deleteById(productId);
    }
}

代碼解釋:

  • getAllProducts() 方法

    • 使用 @DataSource("slave") 注解,從庫將執(zhí)行該方法中的查詢操作。
    • 適用于讀取類操作,減輕主庫壓力。
  • addProduct()、updateProduct() 和 deleteProductById() 方法

    • 這些方法使用 @DataSource("master") 注解,因此會(huì)走主庫。
    • 適用于寫操作(新增、修改、刪除),確保數(shù)據(jù)的強(qiáng)一致性和實(shí)時(shí)性。

4.3 注意事項(xiàng)

在實(shí)現(xiàn)讀寫分離時(shí),以下幾點(diǎn)需要注意:

  • 主從數(shù)據(jù)一致性:從庫的數(shù)據(jù)源于主庫的復(fù)制,所以存在一定的延遲。對(duì)于不允許數(shù)據(jù)延遲的操作,建議強(qiáng)制使用主庫。比如訂單支付或庫存更新等操作,通常對(duì)實(shí)時(shí)性要求較高,應(yīng)直接走主庫。

  • 事務(wù)管理:在事務(wù)中進(jìn)行讀操作,可能會(huì)導(dǎo)致數(shù)據(jù)源切換失效,因?yàn)樵谑聞?wù)中默認(rèn)會(huì)使用主庫。這種情況下,可以使用 @Transactional(readOnly = true) 標(biāo)記方法為只讀事務(wù),讓 Spring 在事務(wù)中仍使用從庫。

  • 線程安全:因?yàn)閿?shù)據(jù)源切換是基于 ThreadLocal 實(shí)現(xiàn)的,所以多線程環(huán)境下可以安全地設(shè)置和切換數(shù)據(jù)源標(biāo)識(shí)。然而,如果有異步操作,可能會(huì)導(dǎo)致數(shù)據(jù)源信息傳遞失效,需要特別注意。

5.測(cè)試和驗(yàn)證

完成 Spring Boot 項(xiàng)目中多數(shù)據(jù)源的配置之后,需要測(cè)試項(xiàng)目是否能夠正確地實(shí)現(xiàn)讀寫分離。主要步驟包括:檢查 MySQL 主庫和從庫的服務(wù)狀態(tài)、啟動(dòng)項(xiàng)目、編寫并運(yùn)行測(cè)試類,以及驗(yàn)證主從數(shù)據(jù)庫的數(shù)據(jù)同步情況。

5.1 檢查 MySQL 主庫和從庫的服務(wù)狀態(tài)

要確保 Spring Boot 項(xiàng)目能夠連接到主從數(shù)據(jù)庫,首先需要確認(rèn) MySQL 主庫和從庫的服務(wù)狀態(tài)。如果主庫和從庫未啟動(dòng),Spring Boot 應(yīng)用將無法連接數(shù)據(jù)庫。

5.1.1 使用命令行檢查 MySQL 服務(wù)狀態(tài)

在主庫和從庫的服務(wù)器上,可以使用以下命令檢查 MySQL 服務(wù)狀態(tài):

# 檢查 MySQL 服務(wù)是否正在運(yùn)行
sudo systemctl status mysql

如果顯示 active (running),則表示 MySQL 服務(wù)正在運(yùn)行。

5.1.2 使用命令行啟動(dòng) MySQL 服務(wù)

如果 MySQL 服務(wù)未運(yùn)行,可以使用以下命令啟動(dòng):

# 啟動(dòng) MySQL 服務(wù)
sudo systemctl start mysql

啟動(dòng)服務(wù)后,可以再次使用 status 命令檢查服務(wù)狀態(tài),確保 MySQL 服務(wù)已啟動(dòng)。

注意:如果主庫和從庫在不同的服務(wù)器上,您需要分別在主庫服務(wù)器和從庫服務(wù)器上執(zhí)行上述命令。

5.2 使用 IntelliJ IDEA 啟動(dòng) Spring Boot 項(xiàng)目

在確認(rèn) MySQL 主庫和從庫均已啟動(dòng)后,可以啟動(dòng) Spring Boot 項(xiàng)目。

5.2.1 在 IntelliJ IDEA 中啟動(dòng) Spring Boot 項(xiàng)目

  • 打開項(xiàng)目:在 IntelliJ IDEA 中打開您的 Spring Boot 項(xiàng)目。
  • 定位主類:在項(xiàng)目的 src/main/java 目錄中,找到主類(通常是帶有 @SpringBootApplication 注解的類,比如 YourApplication 類)。
  • 運(yùn)行項(xiàng)目:右鍵點(diǎn)擊主類文件,選擇“Run ‘YourApplication’”(運(yùn)行 YourApplication)選項(xiàng)。IDEA 將會(huì)在控制臺(tái)顯示啟動(dòng)日志。

5.2.2 檢查控制臺(tái)輸出

項(xiàng)目啟動(dòng)后,檢查 IDEA 控制臺(tái)的日志輸出,確保沒有報(bào)錯(cuò)信息。如果看到類似以下內(nèi)容,則說明項(xiàng)目啟動(dòng)成功:

INFO 12345 --- [main] com.example.YourApplication       : Started YourApplication in 3.456 seconds (JVM running for 4.123)

5.3 編寫測(cè)試類,測(cè)試讀寫操作是否按照預(yù)期走對(duì)應(yīng)的數(shù)據(jù)源

在項(xiàng)目啟動(dòng)后,我們可以編寫測(cè)試類,通過測(cè)試 Spring Boot 項(xiàng)目中是否實(shí)現(xiàn)了主從分離(讀操作走從庫、寫操作走主庫)。

5.3.1 創(chuàng)建測(cè)試類

在項(xiàng)目的 src/test/java 目錄下,創(chuàng)建一個(gè)新的測(cè)試類,例如 UserServiceTest,用于測(cè)試服務(wù)類中的讀寫方法。以下是測(cè)試類的示例代碼:

import com.example.service.UserService;
import com.example.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class UserServiceTest {

    @Autowired
    private UserService userService;

    // 測(cè)試讀操作
    @Test
    public void testReadOperation() {
        // 調(diào)用讀取用戶的方法
        System.out.println("Executing read operation (should use slave database)...");
        userService.getUsers();
    }

    // 測(cè)試寫操作
    @Test
    public void testWriteOperation() {
        // 創(chuàng)建一個(gè)新的用戶
        User user = new User();
        user.setName("Test User");
        user.setEmail("testuser@example.com");

        // 調(diào)用保存用戶的方法
        System.out.println("Executing write operation (should use master database)...");
        userService.saveUser(user);
    }
}

代碼說明

  • @SpringBootTest:該注解用于在測(cè)試類中啟動(dòng) Spring Boot 上下文。它會(huì)自動(dòng)加載配置文件和應(yīng)用上下文,確保測(cè)試類中可以注入依賴。
  • @Autowired:注入 UserService,以便在測(cè)試方法中調(diào)用 getUsers 和 saveUser 方法。
  • @Test:每個(gè)測(cè)試方法都使用 @Test 注解,表明這是一個(gè)測(cè)試用例,測(cè)試框架會(huì)自動(dòng)運(yùn)行帶有 @Test 的方法。

測(cè)試類的測(cè)試方法

  • testReadOperation:測(cè)試從庫的讀取操作。

    • 該方法會(huì)調(diào)用 userService.getUsers(),這應(yīng)該會(huì)使用從庫來執(zhí)行查詢操作。我們可以在日志中確認(rèn)是否成功走到了從庫。
  • testWriteOperation:測(cè)試主庫的寫入操作。

    • 該方法會(huì)創(chuàng)建一個(gè)新用戶并調(diào)用 userService.saveUser(user),應(yīng)該會(huì)使用主庫來執(zhí)行插入操作??梢栽谌罩局胁榭词欠癯晒κ褂弥鲙?。

5.3.3 在 IntelliJ IDEA 中運(yùn)行測(cè)試

在 IntelliJ IDEA 中可以通過以下步驟運(yùn)行測(cè)試類:

  • 運(yùn)行單個(gè)測(cè)試方法:在 testReadOperation 或 testWriteOperation 方法上右鍵點(diǎn)擊,選擇“Run ‘testReadOperation’”或“Run ‘testWriteOperation’”來運(yùn)行特定測(cè)試。
  • 運(yùn)行整個(gè)測(cè)試類:在 UserServiceTest 類名上右鍵點(diǎn)擊,選擇“Run ‘UserServiceTest’”,以運(yùn)行所有測(cè)試方法。

5.3.4 檢查測(cè)試輸出

在控制臺(tái)中查看輸出信息。如果您在 DynamicDataSource 類中添加了日志信息,可以看到類似以下的日志:

Switching to data source: slave
Executing read operation (should use slave database)...
Switching to data source: master
Executing write operation (should use master database)...
  • 讀操作日志:如果 testReadOperation 的日志顯示 Switching to data source: slave,說明讀操作成功走了從庫。
  • 寫操作日志:如果 testWriteOperation 的日志顯示 Switching to data source: master,說明寫操作成功走了主庫。

5.4 檢查主從數(shù)據(jù)庫的數(shù)據(jù)同步

在驗(yàn)證讀寫操作走了正確的數(shù)據(jù)源后,還需要檢查主從數(shù)據(jù)庫的數(shù)據(jù)同步情況,以確認(rèn)主庫的數(shù)據(jù)更改是否成功同步到從庫。

5.4.1 執(zhí)行寫入操作,檢查數(shù)據(jù)同步

  • 運(yùn)行寫入測(cè)試方法:通過 testWriteOperation 或直接調(diào)用服務(wù)中的寫入方法,向主庫插入新數(shù)據(jù)。

  • 在主庫中檢查數(shù)據(jù):連接到主庫,執(zhí)行以下查詢,確認(rèn)數(shù)據(jù)是否成功插入:

    SELECT * FROM your_database.users WHERE name = 'Test User';
    
  • 在從庫中檢查數(shù)據(jù)同步:稍等片刻后,連接到從庫,執(zhí)行相同的查詢,檢查數(shù)據(jù)是否已同步:

    SELECT * FROM your_database.users WHERE name = 'Test User';
    

    如果從庫中也能查詢到這條記錄,則表明主庫的數(shù)據(jù)成功同步到了從庫。

5.4.2 執(zhí)行更新操作,檢查數(shù)據(jù)同步

  • 運(yùn)行更新操作:在主庫中更新記錄的某個(gè)字段,例如通過 userService.updateUser(user) 方法更新 email 字段(假設(shè)該方法存在),或直接在主庫執(zhí)行更新 SQL 語句:

    UPDATE your_database.users SET email = 'updateduser@example.com' WHERE name = 'Test User';
    
  • 在從庫中檢查數(shù)據(jù)同步:稍等片刻后,在從庫執(zhí)行相同的查詢,確認(rèn) email 字段是否已更新為 'updateduser@example.com'

5.4.3 執(zhí)行刪除操作,檢查數(shù)據(jù)同步

  • 運(yùn)行刪除操作:通過 userService.deleteUserById(userId) 方法(假設(shè)存在)或直接在主庫執(zhí)行刪除語句:

    DELETE FROM your_database.users WHERE name = 'Test User';
    
  • 在從庫中檢查數(shù)據(jù)同步:在從庫中執(zhí)行以下查詢,確認(rèn)數(shù)據(jù)是否已同步刪除:

    SELECT * FROM your_database.users WHERE name = 'Test User';
    

    如果查詢結(jié)果為空,則表明刪除操作已成功同步到從庫。

到此這篇關(guān)于MySQL主從復(fù)制數(shù)據(jù)同步的實(shí)現(xiàn)步驟的文章就介紹到這了,更多相關(guān)MySQL 主從復(fù)制數(shù)據(jù)同步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mysql 5.7.18 zip版安裝配置方法圖文教程(win7)

    mysql 5.7.18 zip版安裝配置方法圖文教程(win7)

    這篇文章主要為大家詳細(xì)介紹了win7下mysql 5.7.8 zip版安裝配置方法圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 保證MySQL與Redis數(shù)據(jù)一致性的6種實(shí)現(xiàn)方案

    保證MySQL與Redis數(shù)據(jù)一致性的6種實(shí)現(xiàn)方案

    這篇文章將聚焦在一個(gè)非常重要且復(fù)雜的問題上:MySQL與Redis數(shù)據(jù)的一致性,當(dāng)我們?cè)趹?yīng)用中同時(shí)使用MySQL和Redis時(shí),如何保證兩者的數(shù)據(jù)一致性呢?下面就來分享幾種實(shí)用的解決方案,需要的朋友可以參考下
    2024-03-03
  • MySQL?數(shù)據(jù)庫的對(duì)庫的操作及其數(shù)據(jù)類型

    MySQL?數(shù)據(jù)庫的對(duì)庫的操作及其數(shù)據(jù)類型

    這篇文章主要介紹了MySQL?數(shù)據(jù)庫的對(duì)庫的操作及其數(shù)據(jù)類型,下面文字圍繞數(shù)據(jù)庫的對(duì)庫的操作及其數(shù)據(jù)類型的相關(guān)資料展開詳細(xì)介紹,需要的小伙伴可以參考一下,希望對(duì)你有所幫助
    2021-12-12
  • MAC下MySQL初始密碼忘記怎么辦

    MAC下MySQL初始密碼忘記怎么辦

    MySQL初始密碼忘記如何解決,這篇文章主要介紹了MAC下MySQL忘記初始密碼的解決辦法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • 用命令創(chuàng)建MySQL數(shù)據(jù)庫(de1)的方法

    用命令創(chuàng)建MySQL數(shù)據(jù)庫(de1)的方法

    下面小編就為大家?guī)硪黄妹顒?chuàng)建MySQL數(shù)據(jù)庫(de1)的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03
  • pymysql.err.DataError:(1264, ")異常的有效解決方法(最新推薦)

    pymysql.err.DataError:(1264, ")異常的有效解決方法(最新推薦)

    遇到pymysql.err.DataError錯(cuò)誤時(shí),錯(cuò)誤代碼1264通常指的是MySQL數(shù)據(jù)庫中的Out of range value for column錯(cuò)誤,這意味著你嘗試插入或更新的數(shù)據(jù)超過了對(duì)應(yīng)數(shù)據(jù)庫列所允許的范圍,這篇文章主要介紹了pymysql.err.DataError:(1264, ")異常的有效問題,需要的朋友可以參考下
    2024-05-05
  • MySQL如何創(chuàng)建視圖

    MySQL如何創(chuàng)建視圖

    這篇文章主要介紹了MySQL如何創(chuàng)建視圖,幫助大家更好的理解和學(xué)習(xí)MySQL,感興趣的朋友可以了解下
    2020-08-08
  • 解讀mysql主從配置及其原理分析(Master-Slave)

    解讀mysql主從配置及其原理分析(Master-Slave)

    在windows下配置的,后面會(huì)在Linux下配置進(jìn)行測(cè)試,需要配置mysql數(shù)據(jù)庫同步的朋友可以參考下。
    2011-05-05
  • 最新mysql-5.7.21安裝和配置方法

    最新mysql-5.7.21安裝和配置方法

    這篇文章主要介紹了最新mysql-5.7.21安裝和配置方法,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-09-09
  • MySQL獲取當(dāng)前時(shí)間的多種方式總結(jié)

    MySQL獲取當(dāng)前時(shí)間的多種方式總結(jié)

    負(fù)責(zé)的項(xiàng)目中使用的是mysql數(shù)據(jù)庫,頁面上要顯示當(dāng)天所注冊(cè)人數(shù)的數(shù)量,獲取當(dāng)前的年月日,下面這篇文章主要給大家總結(jié)介紹了關(guān)于MySQL獲取當(dāng)前時(shí)間的多種方式,需要的朋友可以參考下
    2023-02-02

最新評(píng)論