溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Java程序員干貨學(xué)習(xí)筆記—Spring結(jié)合MyBatis實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離

發(fā)布時(shí)間:2020-08-18 12:50:26 來(lái)源:ITPUB博客 閱讀:137 作者:忙碌的程序員 欄目:編程語(yǔ)言

Java程序員干貨學(xué)習(xí)筆記—Spring結(jié)合MyBatis實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離

隨著系統(tǒng)用戶(hù)訪問(wèn)量的不斷增加,數(shù)據(jù)庫(kù)的頻繁訪問(wèn)將成為我們系統(tǒng)的一大瓶頸之一。由于項(xiàng)目前期用戶(hù)量不大,我們實(shí)現(xiàn)單一的數(shù)據(jù)庫(kù)就能完成。但是后期單一的數(shù)據(jù)庫(kù)根本無(wú)法支撐龐大的項(xiàng)目去訪問(wèn)數(shù)據(jù)庫(kù),那么如何解決這個(gè)問(wèn)題呢?

實(shí)際的應(yīng)用中,數(shù)據(jù)庫(kù)都是讀多寫(xiě)少(讀取數(shù)據(jù)的頻率高,更新數(shù)據(jù)的頻率相對(duì)較少),而讀取數(shù)據(jù)通常耗時(shí)比較長(zhǎng),占用數(shù)據(jù)庫(kù)服務(wù)器的CPU較多,從而影響用戶(hù)體驗(yàn)。我們通常的做法就是把查詢(xún)從主庫(kù)中抽取出來(lái),采用多個(gè)從庫(kù),使用負(fù)載均衡,減輕每個(gè)從庫(kù)的查詢(xún)壓力。

采用讀寫(xiě)分離技術(shù)的目標(biāo):有效減輕Master庫(kù)的壓力,又可以把用戶(hù)查詢(xún)數(shù)據(jù)的請(qǐng)求分發(fā)到不同的Slave庫(kù),從而保證系統(tǒng)的健壯性。我們看下采用讀寫(xiě)分離的背景。

我們?cè)陧?xiàng)目開(kāi)發(fā)初期的時(shí)候就設(shè)計(jì)了一個(gè)簡(jiǎn)單的讀寫(xiě)分離,現(xiàn)在我把demo分享給大家。

采用技術(shù)Spring + mybatis

首先定義一個(gè)annotation

import java.lang.annotation.ElementType;

import java.lang.annotation.Target;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface DataSource {

public String value();

}

再定義一個(gè)HandleDataSource

public class HandleDataSource {

public static final ThreadLocal holder = new ThreadLocal();

public static void putDataSource(String datasource) {

holder.set(datasource);

}

public static String getDataSource() {

return holder.get();

}

}

定義一個(gè)切面

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.reflect.MethodSignature;

public class DataSourceAspect {

public void pointCut() {

};

public void before(JoinPoint point) {

Object target = point.getTarget();// 攔截的實(shí)體類(lèi)

String method = point.getSignature().getName();// 攔截的方法名稱(chēng)

Class[] classz = target.getClass().getInterfaces();

Class[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();// 攔截的方法參數(shù)類(lèi)型

try {

Method m = classz[0].getMethod(method, parameterTypes);

if (m != null && m.isAnnotationPresent(DataSource.class)) {

DataSource data = m.getAnnotation(DataSource.class);

HandleDataSource.putDataSource(data.value());

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

獲取數(shù)據(jù)源

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

public class ChooseDataSource extends AbstractRoutingDataSource {

protected Object determineCurrentLookupKey() {

return HandleDataSource.getDataSource();

}

}

配置XMl

classpath*:mysql.propertiescom.mysql.jdbc.Driver${jdbc.url}${jdbc.user}${jdbc.password}SELECT 1 FROM DUAL32510010000true60com.mysql.jdbc.Driver${jdbc.url.read}${jdbc.user.read}${jdbc.password.read}SELECT 1 FROM DUAL32510010000true60

注解到service接口上面

Java程序員干貨學(xué)習(xí)筆記—Spring結(jié)合MyBatis實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離

數(shù)據(jù)庫(kù)表就一張 根據(jù)mybatis的xml大家自己建一下

另外這里還有一個(gè)瑕疵就是,當(dāng)你使用注解事務(wù)的時(shí)候系統(tǒng)只能讀取默認(rèn)的數(shù)據(jù)源,這個(gè)問(wèn)題主要是因?yàn)閟pring的事務(wù)和自定義的aop存在一個(gè)先后順序的問(wèn)題

Spring中的事務(wù)是通過(guò)aop來(lái)實(shí)現(xiàn)的,當(dāng)我們自己寫(xiě)aop攔截的時(shí)候,會(huì)遇到跟spring的事務(wù)aop執(zhí)行的先后順序問(wèn)題,比如說(shuō)動(dòng)態(tài)切換數(shù)據(jù)源的問(wèn)題,如果事務(wù)在前,數(shù)據(jù)源切換在后,會(huì)導(dǎo)致數(shù)據(jù)源切換失效,所以就用到了Order(排序)這個(gè)關(guān)鍵字.

我們可以通過(guò)在@AspectJ的方法中實(shí)現(xiàn)org.springframework.core.Ordered 這個(gè)接口來(lái)定義order的順序,order 的值越小,說(shuō)明越先被執(zhí)行。

大家對(duì)技術(shù)感興趣的朋友也可以來(lái) 關(guān)注我的微信公眾號(hào) Java填坑之路      也會(huì)分享一些 架構(gòu)技術(shù)資料。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI