原理解析
1. MySQL主從復制(Master-Slave Replication)
- 工作原理:MySQL主從復制通過二進制日志(binary log)來同步數據。主服務器記錄所有更改操作到二進制日志中,從服務器讀取這些日志并執行相應的SQL語句來保持與主服務器的數據一致。
- 延遲問題:由于網絡傳輸和處理時間,從庫可能會有短暫的數據滯后,這對于需要實時一致性的場景是一個挑戰。
2. 讀寫分離
- 目的:提高系統性能和可用性。通過將讀請求分配給從庫,寫請求發送給主庫,可以減少主庫的壓力,提升系統的整體性能。
- 實現方式:可以通過數據庫中間件或框架層面的配置來實現。在這個例子中,我們使用Apache ShardingSphere來實現讀寫分離。
3. 自動故障轉移
- 原理:當檢測到主庫不可用時,系統會自動選擇一個從庫作為新的主庫,并重新調整讀寫分配。這通常涉及到心跳檢測、狀態監控等機制。
- 工具支持:除了ShardingSphere外,還可以使用MHA(MySQL Master High Availability)或其他高可用解決方案。
實現步驟詳解
1. 引入依賴
在pom.xml
中添加必要的依賴,包括Spring Boot Starter、MyBatis Starter以及ShardingSphere:
xml
深色版本
<dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- MyBatis Starter --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><!-- ShardingSphere for read-write splitting --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency>
</dependencies>
2. 配置數據源
編輯application.yml
文件以配置多個數據源,并設置ShardingSphere規則以實現讀寫分離:
yaml
深色版本
spring:shardingsphere:datasource:names: master,slave0,slave1master:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://master_host:3306/your_db?useSSL=false&serverTimezone=UTCusername: your_usernamepassword: your_passwordslave0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://slave0_host:3306/your_db?useSSL=false&serverTimezone=UTCusername: your_usernamepassword: your_passwordslave1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://slave1_host:3306/your_db?useSSL=false&serverTimezone=UTCusername: your_usernamepassword: your_passwordmasterslave:load-balance-algorithm-type: round_robin # 負載均衡策略name: ms_ds # 數據源名稱master-data-source-name: master # 主庫數據源名稱slave-data-source-names: slave0,slave1 # 從庫數據源名稱列表props:sql:show: true # 是否顯示SQL語句
3. 配置MyBatis
創建MyBatis Mapper接口,并使用注解或XML配置SQL語句。這里以注解方式為例:
java
深色版本
package com.example.demo.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;import java.util.List;
import java.util.Map;@Mapper
public interface UserMapper {/*** 查詢所有用戶信息.* 注意:對于查詢操作,ShardingSphere會選擇其中一個從庫來執行查詢。** @return 用戶信息列表*/@Select("SELECT * FROM users")List<Map<String, Object>> findAllUsers();/*** 更新用戶信息.* 注意:寫操作只會針對主庫執行。** @param id 用戶ID* @param newName 新用戶名*/void updateUserById(@Param("id") Long id, @Param("newName") String newName);
}
確保你的Spring Boot應用掃描到Mapper接口。可以在主類上添加@MapperScan
注解:
java
深色版本
package com.example.demo;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
4. 使用Mapper進行數據庫操作
現在你可以在Service層中注入并使用Mapper接口來進行數據庫操作:
java
深色版本
package com.example.demo.service;import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 獲取所有用戶信息.** @return 用戶信息列表*/public List<Map<String, Object>> getAllUsers() {return userMapper.findAllUsers();}/*** 更新用戶名稱.** @param id 用戶ID* @param newName 新用戶名*/public void updateUserName(Long id, String newName) {userMapper.updateUserById(id, newName);}
}
注意事項及最佳實踐
-
事務管理:確保所有寫操作都在同一個事務中執行,并且只對主庫進行寫操作。可以使用
@Transactional
注解來管理事務。 -
數據一致性:考慮到主從復制延遲的問題,在某些場景下(如剛完成寫操作后立即讀取),可能需要直接查詢主庫以保證數據一致性。
-
健康檢查:建議定期監控主從狀態,確保從庫同步正常以及主庫可訪問。可以通過定時任務或者外部工具來實現。
-
性能優化:根據實際業務需求調整負載均衡策略,例如采用權重輪詢或其他高級算法來優化查詢效率。