spring控制數(shù)據(jù)庫讀寫分離(多數(shù)據(jù)源動態(tài)切換)

問題描述:

項目一直是使用同一個數(shù)據(jù)庫進行讀和寫的操作盒蟆,在寫操作時會鎖表飞醉,并且效率低痕惋,后期出現(xiàn)性能問題

原因描述:

項目只能操作一個數(shù)據(jù)源

需求描述:

配置多個數(shù)據(jù)源,利用切面進行動態(tài)切換

解決方案:

修改配置泌豆,并且增加切面進行自動控制

解決方式:

第一步:配置多個數(shù)據(jù)源:

?數(shù)據(jù)源1

<!-- 數(shù)據(jù)源 -->

<bean id="DataSource1" class="com.alibaba.druid.pool.DruidDataSource"

init-method="init" destroy-method="close">

<property name="driverClassName" value="${jdbc.driverClass}" />

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.user}" />

<property name="password" value="${jdbc.password}" />

<property name="filters" value="stat" />

<property name="maxActive" value="1000" />

<property name="initialSize" value="1" />

<property name="maxWait" value="80000" />

<property name="minIdle" value="1" />

<!-- 超過時間限制是否回收 -->

<property name="removeAbandoned" value="true" />

<!-- 超時時間;單位為秒吏饿。120秒=2分鐘 -->

<property name="removeAbandonedTimeout" value="120" />

<!-- 關(guān)閉abanded連接時輸出錯誤日志 -->

<!-- <property name="logAbandoned" value="true" /> -->

<property name="timeBetweenEvictionRunsMillis" value="60000" />

<property name="minEvictableIdleTimeMillis" value="300000" />

<property name="validationQuery" value="SELECT 'x'" />

<property name="testWhileIdle" value="true" />

<property name="testOnBorrow" value="false" />

<property name="testOnReturn" value="false" />

<property name="defaultAutoCommit" value="true" />

</bean>

數(shù)據(jù)源2

<!-- 數(shù)據(jù)源 -->

<bean id="DataSource2" class="com.alibaba.druid.pool.DruidDataSource"

init-method="init" destroy-method="close">

<property name="driverClassName" value="${jdbc.driverClass}" />

<property name="url" value="${jdbc.url2}" />

<property name="username" value="${jdbc.user}" />

<property name="password" value="${jdbc.password}" />

<property name="filters" value="stat" />

<property name="maxActive" value="1000" />

<property name="initialSize" value="1" />

<property name="maxWait" value="80000" />

<property name="minIdle" value="1" />

<!-- 超過時間限制是否回收 -->

<property name="removeAbandoned" value="true" />

<!-- 超時時間踪危;單位為秒。120秒=2分鐘 -->

<property name="removeAbandonedTimeout" value="120" />

<!-- 關(guān)閉abanded連接時輸出錯誤日志 -->

<!-- <property name="logAbandoned" value="true" /> -->

<property name="timeBetweenEvictionRunsMillis" value="60000" />

<property name="minEvictableIdleTimeMillis" value="300000" />

<property name="validationQuery" value="SELECT 'x'" />

<property name="testWhileIdle" value="true" />

<property name="testOnBorrow" value="false" />

<property name="testOnReturn" value="false" />

<property name="defaultAutoCommit" value="true" />

</bean>

第二步:配置選擇數(shù)據(jù)源的bean

a.配置數(shù)據(jù)源切換的bean

<bean id="dataSource" class="com.zsrt.devbase.datesource.DynamicDataSource">

<property name="targetDataSources">

<map key-type="java.lang.String">

<entry value-ref="DataSource1" key="testDataSource1"></entry>

<entry value-ref="DataSource2" key="testDataSource2"></entry>

</map>

</property>

<property name="defaultTargetDataSource" ref="testDataSource1" />

</bean>

?class 為自定義的數(shù)據(jù)源切換控制的bean

在map中猪落,key指向的是后臺需要選擇的數(shù)據(jù)源名稱贞远,value指向的是第一步配置的數(shù)據(jù)源id


b.編寫切換控制器

/**

* 數(shù)據(jù)源的切換與選擇器

* @author leixin

* @Date 2017年4月19日

* @version 1.0

*/

public class DataSourceContextHolder {

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

/**

* @Description: 設(shè)置數(shù)據(jù)源類型

* @param dataSourceType 數(shù)據(jù)庫類型

* @return void

* @throws

*/

public static void setDataSourceType(String dataSourceType) {

System.err.println(dataSourceType);

contextHolder.set(dataSourceType);

}

/**

* @Description: 獲取數(shù)據(jù)源類型

* @param

* @return String

* @throws

*/

public static String getDataSourceType() {

return contextHolder.get();

}

/**

* @Description: 清除數(shù)據(jù)源類型

* @param

* @return void

* @throws

*/

public static void clearDataSourceType() {

contextHolder.remove();

}

}

c.編寫切換控制器

public class DynamicDataSource extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey() {

return DataSourceContextHolder.getDataSourceType();

}

}

以上步驟已經(jīng)完成數(shù)據(jù)庫的手動切換,在控制層可以手動切換笨忌。

具體切換方法為:當(dāng)需要調(diào)用數(shù)據(jù)源A時蓝仲,用靜態(tài)的類去設(shè)置數(shù)據(jù)源A的名字,然后再去調(diào)用service




問題:每次都需要手動切換官疲,有點麻煩袱结,因此想到利用切面控制

在上面的基礎(chǔ)上利用切面控制,最先想到的是切面控制service途凫,但是控制service會和事務(wù)控制切面產(chǎn)生沖突(原因是事務(wù)需要鎖定數(shù)據(jù)源的鏈接垢夹,而當(dāng)前的數(shù)據(jù)源鏈接還沒有進行動態(tài)切換,所以只能選擇默認(rèn)的數(shù)據(jù)源维费,從而導(dǎo)致切換失敼)


思路一:

于是想到切面切入點為控制層,在開啟事務(wù)之前就切換數(shù)據(jù)源犀盟。

思路二:

????? 利用@order注解控制切面的執(zhí)行順序


經(jīng)過上面的分析而晒,思路二明顯優(yōu)于思路一,于是開始嘗試思路二且蓬,在思路二的基礎(chǔ)上欣硼,打算開啟注解切入


第一步:自定義切面注解: ? ??

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface DataSource {

}

第二步:編寫切面:

@Aspect

@Order(0)

public class DataSourceAspect{

@AfterReturning("execution(* com.zsrt.devbase.service.*.*(..))")

public void afterReturning() throws Throwable {

DataSourceContextHolder.clearDataSourceType();

}

@Before("execution(* com.zsrt.devbase.service.*.*(..)) && @annotation(com.zsrt.devbase.annotation.DataSource)")

public void before(JoinPoint jp) throws Throwable {

DataSourceContextHolder.setDataSourceType("testDataSource2");

}

}


第三步:配置事務(wù)切面的執(zhí)行順序:


<aop:config>

<!-- 切點表達式:所有的service類中的方法都會有事務(wù) -->

<aop:pointcut id="appService"

expression="execution(* com.zsrt.devbase.service.*Service*.*(..))" />

<aop:advisor advice-ref="txAdvice" pointcut-ref="appService" order="1" />

</aop:config>

結(jié)果:

經(jīng)測試,程序按照預(yù)期進行執(zhí)行:

先切換了數(shù)據(jù)源,然后開啟了事務(wù)诈胜,最后再執(zhí)行了別的切面

---------------------


原文:https://blog.csdn.net/leixin821792669/article/details/70242397

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豹障,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子焦匈,更是在濱河造成了極大的恐慌血公,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缓熟,死亡現(xiàn)場離奇詭異累魔,居然都是意外死亡,警方通過查閱死者的電腦和手機够滑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門垦写,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人彰触,你說我怎么就攤上這事梯投。” “怎么了况毅?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵分蓖,是天一觀的道長。 經(jīng)常有香客問我尔许,道長么鹤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任味廊,我火速辦了婚禮蒸甜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毡们。我一直安慰自己迅皇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布衙熔。 她就那樣靜靜地躺著登颓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪红氯。 梳的紋絲不亂的頭發(fā)上框咙,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音痢甘,去河邊找鬼喇嘱。 笑死,一個胖子當(dāng)著我的面吹牛塞栅,可吹牛的內(nèi)容都是我干的者铜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼作烟!你這毒婦竟也來了愉粤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤拿撩,失蹤者是張志新(化名)和其女友劉穎衣厘,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體压恒,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡影暴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了探赫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片型宙。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖期吓,靈堂內(nèi)的尸體忽然破棺而出早歇,到底是詐尸還是另有隱情,我是刑警寧澤讨勤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站晨另,受9級特大地震影響潭千,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜借尿,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一刨晴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧路翻,春花似錦狈癞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至掉冶,卻和暖如春真竖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厌小。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工恢共, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人璧亚。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓讨韭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子透硝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理吉嚣,服務(wù)發(fā)現(xiàn),斷路器蹬铺,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法尝哆,類相關(guān)的語法,內(nèi)部類的語法甜攀,繼承相關(guān)的語法秋泄,異常的語法,線程的語...
    子非魚_t_閱讀 31,623評論 18 399
  • IoC 容器 Bean 的作用域 自定義作用域?qū)崿F(xiàn) org.springframework.beans.facto...
    Hsinwong閱讀 2,471評論 0 7
  • 我是一位即將要小升初孩子的媽媽规阀,“小升初”這個詞在很多省有一個再普通不過的意思恒序,但是在我們這里對于很多家...
    桐熹閱讀 677評論 0 1