在SpringBoot+MyBatis項目中實現(xiàn)MySQL讀寫分離的實戰(zhàn)指南
在Spring Boot和MyBatis項目中實現(xiàn)MySQL讀寫分離,主要有兩種思路:一種是在應(yīng)用層通過代碼和配置手動控制,另一種是借助中間件自動路由。
下面是幾種主流的實現(xiàn)方案,并提供一個基于Spring抽象路由數(shù)據(jù)源的實戰(zhàn)指南。
如何選擇實現(xiàn)方案
你可以根據(jù)項目的復(fù)雜度、團隊的技術(shù)棧和運維能力,參考下表進行選擇:

對于大多數(shù)Java開發(fā)者來說,從應(yīng)用層手動分離開始學(xué)習(xí)是最直觀的路徑。
核心實現(xiàn):應(yīng)用層手動分離
這種方法的核心是利用Spring的 AbstractRoutingDataSource 來動態(tài)決定使用哪個數(shù)據(jù)源。
主要步驟
1、配置多個數(shù)據(jù)源
在你的application.yml文件中,分別配置主庫和從庫的連接信息。
spring:
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://master-host:3306/db_name
username: root
password: master-pass
slave:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://slave-host:3306/db_name
username: root
password: slave-pass
2、創(chuàng)建數(shù)據(jù)源上下文持有者
使用ThreadLocal來安全地存儲和獲取當(dāng)前線程需要使用的數(shù)據(jù)源鍵值。
public class DataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public static void setDataSourceType(String dataSourceType) {
CONTEXT_HOLDER.set(dataSourceType);
}
public static String getDataSourceType() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSourceType() {
CONTEXT_HOLDER.remove();
}
}
3、創(chuàng)建動態(tài)數(shù)據(jù)源類
繼承AbstractRoutingDataSource并重寫determineCurrentLookupKey方法,使其從上下文持有者中獲取數(shù)據(jù)源鍵值。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
4、使用AOP自動切換數(shù)據(jù)源
通過切面,根據(jù)方法名或自定義注解自動設(shè)置數(shù)據(jù)源。
@Aspect
@Component
public class DataSourceAspect {
// 攔截所有Mapper層方法
@Before("execution(* com.yourpackage.mapper..*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
// 根據(jù)方法名判斷是讀還是寫
if (methodName.startsWith("get") || methodName.startsWith("select") ||
methodName.startsWith("find") || methodName.startsWith("query")) {
// 讀方法切換到從庫
DataSourceContextHolder.setDataSourceType("slave");
} else {
// 寫方法切換到主庫
DataSourceContextHolder.setDataSourceType("master");
}
}
// 方法執(zhí)行后清理數(shù)據(jù)源設(shè)置
@After("execution(* com.yourpackage.mapper..*.*(..))")
public void afterMethod() {
DataSourceContextHolder.clearDataSourceType();
}
}
5、處理特殊情況:強制讀主庫
在某些需要實時讀取數(shù)據(jù)的場景(如剛寫入后立刻查詢),你可以使用自定義注解來強制方法走主庫。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Master {
}
然后在切面中增加對@Master注解的判斷,優(yōu)先使用主庫。
實施中的關(guān)鍵問題與解決方案
主從延遲問題:這是讀寫分離架構(gòu)中最常見的挑戰(zhàn)。對于需要實時性保證的查詢,可以使用上面提到的@Master注解強制走主庫。
事務(wù)管理:為了確保數(shù)據(jù)一致性,在寫操作(如@Transactional注解的方法)中,整個事務(wù)內(nèi)的所有數(shù)據(jù)庫操作都應(yīng)使用主庫。你可以在事務(wù)開始時就強制指定數(shù)據(jù)源為主庫。
故障轉(zhuǎn)移與監(jiān)控:需要建立從庫健康檢查機制。當(dāng)監(jiān)測到從庫延遲過大或宕機時,應(yīng)能自動將讀請求降級到主庫,保證系統(tǒng)的可用性。
總結(jié)
實現(xiàn)Spring Boot + MyBatis的讀寫分離,應(yīng)用層手動方案適合快速上手和理解原理,而中間件方案則在動態(tài)擴展和運維管理上更有優(yōu)勢。
在學(xué)習(xí)或中小型項目中先從應(yīng)用層方案入手,隨著業(yè)務(wù)規(guī)模擴大,再平滑遷移到ProxySQL或ShardingSphere等更強大的中間件上。
以上就是在SpringBoot+MyBatis項目中實現(xiàn)MySQL讀寫分離的實戰(zhàn)指南的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot MyBatis實現(xiàn)MySQL讀寫分離的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JVM內(nèi)存區(qū)域劃分相關(guān)原理詳解
這篇文章主要介紹了JVM內(nèi)存區(qū)域劃分相關(guān)原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
AsyncConfigurerSupport自定義異步線程池處理異常
這篇文章主要為大家介紹了AsyncConfigurerSupport自定義異步線程池處理異常詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06
基于Properties類操作.properties配置文件方法總結(jié)
這篇文章主要介紹了Properties類操作.properties配置文件方法總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
SpringBoot實戰(zhàn)記錄之?dāng)?shù)據(jù)訪問
對于數(shù)據(jù)訪問層,無論是SQL還是NOSQL,Spring Boot默認(rèn)采用整合Spring Data的方式進行統(tǒng)一處理,添加大量自動配置,屏蔽了很多設(shè)置,下面這篇文章主要介紹了SpringBoot實戰(zhàn)記錄之?dāng)?shù)據(jù)訪問,需要的朋友可以參考下2022-04-04
Java HttpServletResponse響應(yīng)實現(xiàn)過程詳解
這篇文章主要介紹了Java HttpServletResponse響應(yīng)實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-05-05

