最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mybatis-plus @DS實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源原理

 更新時(shí)間:2022年07月08日 16:25:45   作者:silver_eagle  
本文主要介紹了mybatis-plus @DS實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1、mybatis-plus @DS實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源原理

首先mybatis-plus使用com.baomidou.dynamic.datasource.AbstractRoutingDataSource繼承 AbstractDataSource接管數(shù)據(jù)源;具體實(shí)現(xiàn)類(lèi)為com.baomidou.dynamic.datasource.DynamicRoutingDataSource。項(xiàng)目初始化調(diào)用public synchronized void addDataSource(String ds, DataSource dataSource)加載數(shù)據(jù)源,數(shù)據(jù)源存進(jìn)dataSourceMap中。
private Map<String, DataSource> dataSourceMap = new LinkedHashMap<>();

private Map<String, DynamicGroupDataSource> groupDataSources = new ConcurrentHashMap<>();

public synchronized void addDataSource(String ds, DataSource dataSource) {
? ? if (p6spy) {
? ? ? dataSource = new P6DataSource(dataSource);
? ? }
? ? dataSourceMap.put(ds, dataSource);
? ? if (ds.contains(UNDERLINE)) {
? ? ? String group = ds.split(UNDERLINE)[0];
? ? ? if (groupDataSources.containsKey(group)) {
? ? ? ? groupDataSources.get(group).addDatasource(dataSource);
? ? ? } else {
? ? ? ? try {
? ? ? ? ? DynamicGroupDataSource groupDatasource = new DynamicGroupDataSource(group,
? ? ? ? ? ? ? strategy.newInstance());
? ? ? ? ? groupDatasource.addDatasource(dataSource);
? ? ? ? ? groupDataSources.put(group, groupDatasource);
? ? ? ? } catch (Exception e) {
? ? ? ? ? log.error("dynamic-datasource - add the datasource named [{}] error", ds, e);
? ? ? ? ? dataSourceMap.remove(ds);
? ? ? ? }
? ? ? }
? ? }
? ? log.info("dynamic-datasource - load a datasource named [{}] success", ds);
? }

進(jìn)行數(shù)據(jù)操作時(shí),方法會(huì)被com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor攔截,

public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor {

? /**
? ?* The identification of SPEL.
? ?*/
? private static final String DYNAMIC_PREFIX = "#";
? private static final DynamicDataSourceClassResolver RESOLVER = new DynamicDataSourceClassResolver();
? @Setter
? private DsProcessor dsProcessor;

? @Override
? public Object invoke(MethodInvocation invocation) throws Throwable {
? ? try {
? ? ? DynamicDataSourceContextHolder.push(determineDatasource(invocation));
? ? ? return invocation.proceed();
? ? } finally {
? ? ? DynamicDataSourceContextHolder.poll();
? ? }
? }

? private String determineDatasource(MethodInvocation invocation) throws Throwable {
? ? Method method = invocation.getMethod();
? ? DS ds = method.isAnnotationPresent(DS.class)
? ? ? ? ? method.getAnnotation(DS.class)
? ? ? ? : AnnotationUtils.findAnnotation(RESOLVER.targetClass(invocation), DS.class);
? ? String key = ds.value();
? ? return (!key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) ? dsProcessor
? ? ? ? .determineDatasource(invocation, key) : key;
? }
}

攔截器首先從被攔截的方法或者類(lèi)(一般@DS注解用于Service,也可用于Mapper和Controller)上尋找@DS注解,獲取到@DS注解的值后將其存入com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;DynamicDataSourceContextHolder使用ThreadLocal存儲(chǔ)當(dāng)前線程的數(shù)據(jù)源名。

public final class DynamicDataSourceContextHolder {

? /**
? ?* 為什么要用鏈表存儲(chǔ)(準(zhǔn)確的是棧)
? ?* 為了支持嵌套切換,如ABC三個(gè)service都是不同的數(shù)據(jù)源
? ?* 其中A的某個(gè)業(yè)務(wù)要調(diào)B的方法,B的方法需要調(diào)用C的方法。一級(jí)一級(jí)調(diào)用切換,形成了鏈。
? ?* 傳統(tǒng)的只設(shè)置當(dāng)前線程的方式不能滿足此業(yè)務(wù)需求,必須模擬棧,后進(jìn)先出。
? ?*/
? @SuppressWarnings("unchecked")
? private static final ThreadLocal<Deque<String>> LOOKUP_KEY_HOLDER = new ThreadLocal() {
? ? @Override
? ? protected Object initialValue() {
? ? ? return new ArrayDeque();
? ? }
? };

? private DynamicDataSourceContextHolder() {
? }

? /**
? ?* 獲得當(dāng)前線程數(shù)據(jù)源
? ?* @return 數(shù)據(jù)源名稱(chēng)
? ?*/
? public static String peek() {
? ? return LOOKUP_KEY_HOLDER.get().peek();
? }

? /**
? ?* 設(shè)置當(dāng)前線程數(shù)據(jù)源
? ?* 如非必要不要手動(dòng)調(diào)用,調(diào)用后確保最終清除
? ?* @param ds 數(shù)據(jù)源名稱(chēng)
? ?*/
? public static void push(String ds) {
? ? LOOKUP_KEY_HOLDER.get().push(StringUtils.isEmpty(ds) ? "" : ds);
? }

? /**
? ?* 清空當(dāng)前線程數(shù)據(jù)源
? ?* 如果當(dāng)前線程是連續(xù)切換數(shù)據(jù)源 只會(huì)移除掉當(dāng)前線程的數(shù)據(jù)源名稱(chēng)
? ?*/
? public static void poll() {
? ? Deque<String> deque = LOOKUP_KEY_HOLDER.get();
? ? deque.poll();
? ? if (deque.isEmpty()) {
? ? ? LOOKUP_KEY_HOLDER.remove();
? ? }
? }

? /**
? ?* 強(qiáng)制清空本地線程
? ?* 防止內(nèi)存泄漏,如手動(dòng)調(diào)用了push可調(diào)用此方法確保清除
? ?*/
? public static void clear() {
? ? LOOKUP_KEY_HOLDER.remove();
? }
}

進(jìn)行數(shù)據(jù)操作時(shí),會(huì)調(diào)用org.springframework.jdbc.datasource.getConnection()方法;getConnection()方法最終調(diào)用了com.baomidou.dynamic.datasource.AbstractRoutingDataSource的getConnection()方法;

  @Override
  public Connection getConnection() throws SQLException {
    return determineDataSource().getConnection();
  }

determineDataSource()由子類(lèi)com.baomidou.dynamic.datasource.DynamicRoutingDataSource實(shí)現(xiàn),可以看到DynamicRoutingDataSource從DynamicDataSourceContextHolder獲取數(shù)據(jù)源名稱(chēng),這個(gè)在之前攔截器處理存進(jìn)ThreadLocal中,如果有數(shù)據(jù)源名稱(chēng)則從dataSourceMap中獲取,沒(méi)有則獲取默認(rèn)的primary數(shù)據(jù)源。

public DataSource determineDataSource() {
? ? return getDataSource(DynamicDataSourceContextHolder.peek());
}

public DataSource getDataSource(String ds) {
? ? if (StringUtils.isEmpty(ds)) {
? ? ? ? return determinePrimaryDataSource();
? ? } else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
? ? ? ? log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
? ? ? ? return groupDataSources.get(ds).determineDataSource();
? ? } else if (dataSourceMap.containsKey(ds)) {
? ? ? ? log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
? ? ? ? return dataSourceMap.get(ds);
? ? }
? ? if (strict) {
? ? ? ? throw new RuntimeException("dynamic-datasource could not find a datasource named" + ds);
? ? }
? ? return determinePrimaryDataSource();
}

private DataSource determinePrimaryDataSource() {
? ? log.debug("dynamic-datasource switch to the primary datasource");
? ? return groupDataSources.containsKey(primary) ? groupDataSources.get(primary)
? ? ? ? .determineDataSource() : dataSourceMap.get(primary);
}

此時(shí)的數(shù)據(jù)源已經(jīng)切換成了我們需要的數(shù)據(jù)源。

數(shù)據(jù)操作完成后,方法返回第二步中的攔截器,執(zhí)行DynamicDataSourceContextHolder.poll();清除掉此次的數(shù)據(jù)源,避免影響后續(xù)數(shù)據(jù)操作。

附上動(dòng)態(tài)數(shù)據(jù)源相關(guān)配置

spring:
  application:
    name: 
  datasource:
    dynamic:
      primary: dataSource1
      datasource:
        dataSource1:
          type: com.alibaba.druid.pool.DruidDataSource
          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
          url: jdbc:sqlserver://localhost:1433;database=dataSource1
          username: 
          password: 
        dataSource2:
          type: com.alibaba.druid.pool.DruidDataSource
          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
          url: jdbc:sqlserver://localhost:1433;instanceName=sqlserver2017;DatabaseName=dataSource2
          username: 
          password: 

pom.xml

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>2.5.6</version>
</dependency>

相應(yīng)類(lèi)

@Service
//@DS("dataSource2") 放在類(lèi)上就是類(lèi)下所有方法都使用這個(gè)數(shù)據(jù)源。
public class XXXServiceImpl extends BaseServiceImpl<XXXMapper, XXXBean> implements XXXService {

? ? @DS("dataSource1")
? ? public void selectDataFromSource1() {
? ? ? ?// do somethinng;
? ? }
? ??
? ? @DS("dataSource2")
? ? public void selectDataFromSource1() {
? ? ? ?// do somethinng;
? ? }
}

**注意:**不可在事務(wù)中切換數(shù)據(jù)庫(kù),保證事務(wù)需要方法使用同一連接,使用@DS(dataSource1)方法調(diào)用@DS(dataSource2)無(wú)法切換連接,會(huì)導(dǎo)致方法報(bào)錯(cuò)。

到此這篇關(guān)于mybatis-plus @DS實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源原理的文章就介紹到這了,更多相關(guān)mybatis-plus @DS動(dòng)態(tài)切換數(shù)據(jù)源內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot多種自定義錯(cuò)誤頁(yè)面方式小結(jié)

    SpringBoot多種自定義錯(cuò)誤頁(yè)面方式小結(jié)

    這篇文章主要介紹了SpringBoot多種自定義錯(cuò)誤頁(yè)面方式小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 淺談JMeter engine啟動(dòng)原理

    淺談JMeter engine啟動(dòng)原理

    本文主要介紹jmeter在控制臺(tái)在點(diǎn)擊執(zhí)行之后底層所做的一些主要事情及內(nèi)容,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • SpringBoot+logback默認(rèn)日志的配置和使用方式

    SpringBoot+logback默認(rèn)日志的配置和使用方式

    這篇文章主要介紹了SpringBoot+logback默認(rèn)日志的配置和使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 使用Spring組合自定義的注釋 mscharhag操作

    使用Spring組合自定義的注釋 mscharhag操作

    這篇文章主要介紹了使用Spring組合自定義的注釋 mscharhag,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的工作或?qū)W習(xí)有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 關(guān)于fastjson的@JSONField注解的一些問(wèn)題(詳解)

    關(guān)于fastjson的@JSONField注解的一些問(wèn)題(詳解)

    下面小編就為大家?guī)?lái)一篇關(guān)于fastjson的@JSONField注解的一些問(wèn)題(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • 深入理解HashMap各個(gè)方法的源碼

    深入理解HashMap各個(gè)方法的源碼

    這篇文章主要介紹了深入理解HashMap各個(gè)方法的源碼,HashMap初始容量不能為負(fù)數(shù),若初始容量大于最大容量,則讓它等于最大容量,負(fù)載因子必須大于0,并且傳入的initialCapacity不是HashMap的容量大小,需要的朋友可以參考下
    2023-12-12
  • Java 如何遍歷JsonObject對(duì)象

    Java 如何遍歷JsonObject對(duì)象

    這篇文章主要介紹了Java 如何遍歷JsonObject對(duì)象?今天小編就為大家分享一篇Java遍歷JsonObject對(duì)象案例,希望對(duì)大家有所幫助吧
    2021-01-01
  • SpringMVC Controller解析ajax參數(shù)過(guò)程詳解

    SpringMVC Controller解析ajax參數(shù)過(guò)程詳解

    這篇文章主要介紹了SpringMVC Controller解析ajax參數(shù)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • java 文件的操作Path、Paths、Files詳解

    java 文件的操作Path、Paths、Files詳解

    Java NIO(New I/O)是Java 7中引入的一項(xiàng)重要特性,旨在提供一種更加靈活和高效的文件處理方式,NIO.2主要通過(guò)Path、Paths和Files三個(gè)核心組件來(lái)實(shí)現(xiàn)對(duì)文件和目錄的操作,本文給大家介紹java 文件的操作Path、Paths、Files的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2024-10-10
  • Dwr3.0純注解(純Java Code配置)配置與應(yīng)用淺析二之前端調(diào)用后端

    Dwr3.0純注解(純Java Code配置)配置與應(yīng)用淺析二之前端調(diào)用后端

    我們講到了后端純Java Code的Dwr3配置,完全去掉了dwr.xml配置文件,但是對(duì)于使用注解的類(lèi)卻沒(méi)有使用包掃描,而是在Servlet初始化參數(shù)的classes里面加入了我們的Service組件的聲明暴露,對(duì)于這個(gè)問(wèn)題需要后面我們?cè)偌?xì)細(xì)研究下這篇文章,主要分析介紹前端怎么直接調(diào)用后端
    2016-04-04

最新評(píng)論

南雄市| 崇州市| 丰原市| 息烽县| 武威市| 新余市| 同德县| 上高县| 固原市| 茌平县| 嘉善县| 遂平县| 即墨市| 郑州市| 盐山县| 嘉峪关市| 根河市| 互助| 霸州市| 弥勒县| 博乐市| 来宾市| 平顶山市| 马关县| 三门县| 南汇区| 台湾省| 阿勒泰市| 天等县| 舟山市| 华池县| 滨海县| 墨江| 龙门县| 松江区| 甘孜县| 颍上县| 元朗区| 吉林市| 乐山市| 彭阳县|