springboot項目自定義注解實現(xiàn)的多數(shù)據(jù)源切換

一宋渔、主要依賴

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.4.RELEASE</version><relativePath/></parent><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.1.4.RELEASE</version></dependency>dependency>

? ? <groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency>

二、yml

# 數(shù)據(jù)源配置

spring:

? ? datasource:

? ? ? ? type: com.alibaba.druid.pool.DruidDataSource

? ? ? ? driverClassName: com.mysql.jdbc.Driver

? ? ? ? druid:

? ? ? ? ? ? # 主庫數(shù)據(jù)源

? ? ? ? ? ? master:

? ? ? ? ? ? ? ? url: jdbc:mysql://127.0.0.1:3306/master?characterEncoding=UTF-8? ? ? ? ? ? ? ? username: root

? ? ? ? ? ? ? ? password: root

? ? ? ? ? ? #樹熊數(shù)據(jù)源

? ? ? ? ? ? slave:

? ? ? ? ? ? ? ? enabled : true? ? ? ? ? ? ? ? url: jdbc:mysql:////127.0.0.1:3306/slave?characterEncoding=UTF-8? ? ? ? ? ? ? ? username: root

? ? ? ? ? ? ? ? password: root


? ? ? ? ? ? # 初始連接數(shù)

? ? ? ? ? ? initial-size: 10? ? ? ? ? ? # 最大連接池數(shù)量

? ? ? ? ? ? max-active: 100? ? ? ? ? ? # 最小連接池數(shù)量

? ? ? ? ? ? min-idle: 10? ? ? ? ? ? # 配置獲取連接等待超時的時間

? ? ? ? ? ? max-wait: 60000? ? ? ? ? ? # 打開PSCache惊科,并且指定每個連接上PSCache的大小

? ? ? ? ? ? pool-prepared-statements:true? ? ? ? ? ? max-pool-prepared-statement-per-connection-size: 20? ? ? ? ? ? # 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接含衔,單位是毫秒

? ? ? ? ? ? timeBetweenEvictionRunsMillis: 60000? ? ? ? ? ? # 配置一個連接在池中最小生存的時間蹄咖,單位是毫秒

? ? ? ? ? ? min-evictable-idle-time-millis: 300000? ? ? ? ? ? validation-query: SELECT 1 FROM DUAL

? ? ? ? ? ? test-while-idle:true? ? ? ? ? ? test-on-borrow:false? ? ? ? ? ? test-on-return:false? ? ? ? ? ? stat-view-servlet:

? ? ? ? ? ? ? ? enabled: true? ? ? ? ? ? ? ? url-pattern: /druid/*? ? ? ? ? ? filter:

? ? ? ? ? ? ? ? stat:

? ? ? ? ? ? ? ? ? ? log-slow-sql: true

? ? ? ? ? ? ? ? ? ? slow-sql-millis: 1000

? ? ? ? ? ? ? ? ? ? merge-sql: false

? ? ? ? ? ? ? ? wall:

? ? ? ? ? ? ? ? ? ? config:

? ? ? ? ? ? ? ? ? ? ? ? multi-statement-allow: true

三泽示、實現(xiàn)

3.1、@DataSource和DataSourceType

/** * 數(shù)據(jù)源

* @author DUCHONG

*/publicenum DataSourceType

{

? ? /**? ? * 主庫

? ? */? ? MASTER,

? ? /**? ? * 從庫

? ? */? ? SLAVE

}

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 自定義多數(shù)據(jù)源切換注解

*

* @author DUCHONG

*/@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)public@interface DataSource

{

? ? /**? ? * 切換數(shù)據(jù)源名稱

? ? */publicDataSourceType value()default DataSourceType.MASTER;

}

3.2腥放、DynamicDataSourceContextHolder

import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * 數(shù)據(jù)源切換處理

*

* @author DUCHONG

*/publicclass DynamicDataSourceContextHolder

{

? ? publicstaticfinalLogger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

? ? /**? ? * 使用ThreadLocal維護變量泛啸,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,

? ? *? 所以每一個線程都可以獨立地改變自己的副本秃症,而不會影響其它線程所對應的副本候址。

? ? */privatestaticfinalThreadLocal CONTEXT_HOLDER =newThreadLocal<>();

? ? /**? ? * 設置數(shù)據(jù)源的變量

? ? */publicstaticvoid setDateSourceType(String dsType)

? ? {

? ? ? ? log.info("切換到{}數(shù)據(jù)源", dsType);

? ? ? ? CONTEXT_HOLDER.set(dsType);

? ? }

? ? /**? ? * 獲得數(shù)據(jù)源的變量

? ? */publicstatic String getDateSourceType()

? ? {

? ? ? ? return CONTEXT_HOLDER.get();

? ? }

? ? /**? ? * 清空數(shù)據(jù)源變量

? ? */publicstaticvoid clearDateSourceType()

? ? {

? ? ? ? CONTEXT_HOLDER.remove();

? ? }

}

3.3、繼承AbstractRoutingDataSource

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;import java.util.Map;/** * 動態(tài)數(shù)據(jù)源

*

* @author DUCHONG

*/publicclassDynamicDataSourceextends AbstractRoutingDataSource

{

? ? publicDynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources)

? ? {

? ? ? ? super.setDefaultTargetDataSource(defaultTargetDataSource);

? ? ? ? super.setTargetDataSources(targetDataSources);

? ? ? ? super.afterPropertiesSet();

? ? }

? ? @Override

? ? protected Object determineCurrentLookupKey()

? ? {

? ? ? ? return DynamicDataSourceContextHolder.getDateSourceType();

? ? }

}

3.4种柑、定義切面

import com.starfast.admin.common.annotation.DataSource;import com.starfast.admin.datasource.DynamicDataSourceContextHolder;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import java.lang.reflect.Method;/** * 多數(shù)據(jù)源處理

* @author DUCHONG

*/@Aspect

@Order(1)

@Componentpublicclass DataSourceAspect

{

? ? protectedLogger logger = LoggerFactory.getLogger(getClass());

? ? @Pointcut("@annotation(com.duchong.common.annotation.DataSource)")

? ? publicvoid dsPointCut()

? ? {

? ? }

? ? @Around("dsPointCut()")

? ? publicObject around(ProceedingJoinPoint point)throws Throwable

? ? {

? ? ? ? MethodSignature signature = (MethodSignature) point.getSignature();

? ? ? ? Method method = signature.getMethod();

? ? ? ? DataSource dataSource = method.getAnnotation(DataSource.class);

? ? ? ? if(null!=dataSource)

? ? ? ? {

? ? ? ? ? ? DynamicDataSourceContextHolder.setDateSourceType(dataSource.value().name());

? ? ? ? }

? ? ? ? try? ? ? ? {

? ? ? ? ? ? return point.proceed();

? ? ? ? }

? ? ? ? finally? ? ? ? {

? ? ? ? ? ? // 銷毀數(shù)據(jù)源 在執(zhí)行方法之后? ? ? ? ? ? DynamicDataSourceContextHolder.clearDateSourceType();

? ? ? ? }

? ? }

}

3.5岗仑、@Configuration

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;import com.starfast.admin.common.enums.DataSourceType;import com.starfast.admin.datasource.DynamicDataSource;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import javax.sql.DataSource;import java.util.HashMap;import java.util.Map;/** * druid 配置多數(shù)據(jù)源

*

* @author DUCHONG

*/@Configurationpublicclass DruidConfig

{

? ? @Bean

? ? @ConfigurationProperties("spring.datasource.druid.master")

? ? public DataSource masterDataSource()

? ? {

? ? ? ? return DruidDataSourceBuilder.create().build();

? ? }

? ? @Bean

? ? @ConfigurationProperties("spring.datasource.druid.slave")

? ? @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")

? ? public DataSource slaveDataSource()

? ? {

? ? ? ? return DruidDataSourceBuilder.create().build();

? ? }

? ? @Bean(name = "dynamicDataSource")

? ? @Primary

? ? public DynamicDataSource dataSource()

? ? {

? ? ? ? Map targetDataSources =newHashMap<>();

? ? ? ? targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource());

? ? ? ? targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource());

? ? ? ? returnnew DynamicDataSource(masterDataSource(), targetDataSources);

? ? }

}

3.6、使用

需要切換數(shù)據(jù)源的方法上加

@DataSource(value = DataSourceType.SLAVE)

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末聚请,一起剝皮案震驚了整個濱河市荠雕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驶赏,老刑警劉巖炸卑,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異煤傍,居然都是意外死亡盖文,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門蚯姆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來五续,“玉大人,你說我怎么就攤上這事龄恋「砑荩” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵郭毕,是天一觀的道長它碎。 經(jīng)常有香客問我显押,道長,這世上最難降的妖魔是什么煮落? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮蝉仇,結果婚禮上殖蚕,老公的妹妹穿的比我還像新娘。我一直安慰自己沉迹,他們只是感情好,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布鞭呕。 她就那樣靜靜地躺著,像睡著了一般葫松。 火紅的嫁衣襯著肌膚如雪瓦糕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天腋么,我揣著相機與錄音咕娄,去河邊找鬼。 笑死珊擂,一個胖子當著我的面吹牛圣勒,可吹牛的內容都是我干的。 我是一名探鬼主播摧扇,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼圣贸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了扛稽?” 一聲冷哼從身側響起吁峻,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎庇绽,沒想到半個月后锡搜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體橙困,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡瞧掺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了凡傅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辟狈。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖夏跷,靈堂內的尸體忽然破棺而出哼转,到底是詐尸還是另有隱情,我是刑警寧澤槽华,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布壹蔓,位于F島的核電站,受9級特大地震影響猫态,放射性物質發(fā)生泄漏佣蓉。R本人自食惡果不足惜披摄,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勇凭。 院中可真熱鬧疚膊,春花似錦、人聲如沸虾标。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽璧函。三九已至傀蚌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柳譬,已是汗流浹背喳张。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留美澳,地道東北人销部。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓制跟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雨膨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內容