亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳細(xì)聊聊SpringBoot中動態(tài)切換數(shù)據(jù)源的方法

 更新時間:2021年09月29日 12:58:09   作者:Nicksxs  
在大型分布式項目中,經(jīng)常會出現(xiàn)多數(shù)據(jù)源的情況,下面這篇文章主要給大家介紹了關(guān)于SpringBoot中動態(tài)切換數(shù)據(jù)源的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

其實這個表示有點不太對,應(yīng)該是 Druid 動態(tài)切換數(shù)據(jù)源的方法,只是應(yīng)用在了 springboot 框架中,準(zhǔn)備代碼準(zhǔn)備了半天,之前在一次數(shù)據(jù)庫遷移中使用了,發(fā)現(xiàn) Druid 還是很強(qiáng)大的,用來做動態(tài)數(shù)據(jù)源切換很方便。

首先這里的場景跟我原來用的有點點區(qū)別,在項目中使用的是通過配置中心控制數(shù)據(jù)源切換,統(tǒng)一切換,而這里的例子多加了個可以根據(jù)接口注解配置

第一部分是最核心的,如何基于 Spring JDBC 和 Druid 來實現(xiàn)數(shù)據(jù)源切換,是繼承了org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 這個類,他的determineCurrentLookupKey方法會被調(diào)用來獲得用來決定選擇那個數(shù)據(jù)源的對象,也就是 lookupKey,也可以通過這個類看到就是通過這個 lookupKey 來路由找到數(shù)據(jù)源。

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        if (DatabaseContextHolder.getDatabaseType() != null) {
            return DatabaseContextHolder.getDatabaseType().getName();
        }
        return DatabaseType.MASTER1.getName();
    }
}

而如何使用這個 lookupKey 呢,就涉及到我們的 DataSource 配置了,原來就是我們可以直接通過spring 的 jdbc 配置數(shù)據(jù)源,像這樣

現(xiàn)在我們要使用 Druid 作為數(shù)據(jù)源了,然后配置 DynamicDataSource的參數(shù),通過 key 來選擇對應(yīng)的 DataSource,也就是下面配的 master1 和 master2

<bean id="master1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close"
          p:driverClassName="com.mysql.cj.jdbc.Driver"
          p:url="${master1.demo.datasource.url}"
          p:username="${master1.demo.datasource.username}"
          p:password="${master1.demo.datasource.password}"
          p:initialSize="5"
          p:minIdle="1"
          p:maxActive="10"
          p:maxWait="60000"
          p:timeBetweenEvictionRunsMillis="60000"
          p:minEvictableIdleTimeMillis="300000"
          p:validationQuery="SELECT 'x'"
          p:testWhileIdle="true"
          p:testOnBorrow="false"
          p:testOnReturn="false"
          p:poolPreparedStatements="false"
          p:maxPoolPreparedStatementPerConnectionSize="20"
          p:connectionProperties="config.decrypt=true"
          p:filters="stat,config"/>

    <bean id="master2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close"
          p:driverClassName="com.mysql.cj.jdbc.Driver"
          p:url="${master2.demo.datasource.url}"
          p:username="${master2.demo.datasource.username}"
          p:password="${master2.demo.datasource.password}"
          p:initialSize="5"
          p:minIdle="1"
          p:maxActive="10"
          p:maxWait="60000"
          p:timeBetweenEvictionRunsMillis="60000"
          p:minEvictableIdleTimeMillis="300000"
          p:validationQuery="SELECT 'x'"
          p:testWhileIdle="true"
          p:testOnBorrow="false"
          p:testOnReturn="false"
          p:poolPreparedStatements="false"
          p:maxPoolPreparedStatementPerConnectionSize="20"
          p:connectionProperties="config.decrypt=true"
          p:filters="stat,config"/>

    <bean id="dataSource" class="com.nicksxs.springdemo.config.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <!-- master -->
                <entry key="master1" value-ref="master1"/>
                <!-- slave -->
                <entry key="master2" value-ref="master2"/>
            </map>
        </property>
        <property name="defaultTargetDataSource" ref="master1"/>
    </bean>

現(xiàn)在就要回到頭上,介紹下這個DatabaseContextHolder,這里使用了 ThreadLocal 存放這個 DatabaseType,為啥要用這個是因為前面說的我們想要讓接口層面去配置不同的數(shù)據(jù)源,要把持相互隔離不受影響,就使用了 ThreadLocal,關(guān)于它也可以看我前面寫的一篇文章聊聊傳說中的 ThreadLocal,而 DatabaseType 就是個簡單的枚舉

public class DatabaseContextHolder {
    public static final ThreadLocal<DatabaseType> databaseTypeThreadLocal = new ThreadLocal<>();

    public static DatabaseType getDatabaseType() {
        return databaseTypeThreadLocal.get();
    }

    public static void putDatabaseType(DatabaseType databaseType) {
        databaseTypeThreadLocal.set(databaseType);
    }

    public static void clearDatabaseType() {
        databaseTypeThreadLocal.remove();
    }
}
public enum DatabaseType {
    MASTER1("master1", "1"),
    MASTER2("master2", "2");

    private final String name;
    private final String value;

    DatabaseType(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public String getValue() {
        return value;
    }

    public static DatabaseType getDatabaseType(String name) {
        if (MASTER2.name.equals(name)) {
            return MASTER2;
        }
        return MASTER1;
    }
}

這邊可以看到就是通過動態(tài)地通過putDatabaseType設(shè)置lookupKey來進(jìn)行數(shù)據(jù)源切換,要通過接口注解配置來進(jìn)行設(shè)置的話,我們就需要一個注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
    String value();
}

這個注解可以配置在我的接口方法上,比如這樣

public interface StudentService {

    @DataSource("master1")
    public Student queryOne();

    @DataSource("master2")
    public Student queryAnother();

}

通過切面來進(jìn)行數(shù)據(jù)源的設(shè)置

@Aspect
@Component
@Order(-1)
public class DataSourceAspect {

    @Pointcut("execution(* com.nicksxs.springdemo.service..*.*(..))")
    public void pointCut() {

    }


    @Before("pointCut()")
    public void before(JoinPoint point)
    {
        Object target = point.getTarget();
        System.out.println(target.toString());
        String method = point.getSignature().getName();
        System.out.println(method);
        Class<?>[] classz = target.getClass().getInterfaces();
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            Method m = classz[0].getMethod(method, parameterTypes);
            System.out.println("method"+ m.getName());
            if (m.isAnnotationPresent(DataSource.class)) {
                DataSource data = m.getAnnotation(DataSource.class);
                System.out.println("dataSource:"+data.value());
                DatabaseContextHolder.putDatabaseType(DatabaseType.getDatabaseType(data.value()));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @After("pointCut()")
    public void after() {
    DatabaseContextHolder.clearDatabaseType();
    }
}

通過接口判斷是否帶有注解跟是注解的值,DatabaseType 的配置不太好,不過先忽略了,然后在切點后進(jìn)行清理

這是我 master1 的數(shù)據(jù),

master2 的數(shù)據(jù)

然后跑一下簡單的 demo,

@Override
public void run(String...args) {
 LOGGER.info("run here");
 System.out.println(studentService.queryOne());
 System.out.println(studentService.queryAnother());

}

看一下運行結(jié)果

其實這個方法應(yīng)用場景不止可以用來遷移數(shù)據(jù)庫,還能實現(xiàn)精細(xì)化的讀寫數(shù)據(jù)源分離之類的,算是做個簡單記錄和分享。

總結(jié)

到此這篇關(guān)于SpringBoot中動態(tài)切換數(shù)據(jù)源的文章就介紹到這了,更多相關(guān)SpringBoot動態(tài)切換數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實現(xiàn)線程的暫停和恢復(fù)的示例詳解

    Java實現(xiàn)線程的暫停和恢復(fù)的示例詳解

    這幾天的項目中,客戶給了個需求,希望我可以開啟一個任務(wù),想什么時候暫停就什么時候暫停,想什么時候開始就什么時候開始,所以本文小編給大家介紹了Java實現(xiàn)線程的暫停和恢復(fù)的示例,需要的朋友可以參考下
    2023-11-11
  • 詳解Springboot事務(wù)管理

    詳解Springboot事務(wù)管理

    本篇文章主要介紹了詳解Springboot事務(wù)管理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • Java Durid進(jìn)行JDBC連接詳解

    Java Durid進(jìn)行JDBC連接詳解

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章簡單使用Durid進(jìn)行JDBC連接,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-09-09
  • java 兩個數(shù)組合并的幾種方法

    java 兩個數(shù)組合并的幾種方法

    本篇文章主要介紹了java 兩個數(shù)組合并的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Java的long和bigint長度對比詳解

    Java的long和bigint長度對比詳解

    在本文中小編給大家分享了關(guān)于Java的long和bigint長度比較的知識點內(nèi)容,有興趣的朋友們學(xué)習(xí)參考下。
    2019-07-07
  • java對象序列化與反序列化的默認(rèn)格式和json格式使用示例

    java對象序列化與反序列化的默認(rèn)格式和json格式使用示例

    這篇文章主要介紹了java對象序列化與反序列化的默認(rèn)格式和json格式使用示例,需要的朋友可以參考下
    2014-02-02
  • mybatis源碼解讀之executor包語句處理功能

    mybatis源碼解讀之executor包語句處理功能

    這篇文章主要介紹了executor包語句處理功能,mybatis中支持三種語句類型,不同語句類型支持的變量符號不同,下文詳細(xì)內(nèi)容,需要的小伙伴可以參考一下
    2022-02-02
  • Java compareTo用法詳解

    Java compareTo用法詳解

    在Java編程中,有時候我們需要對對象進(jìn)行比較和排序,為了實現(xiàn)這一目標(biāo),Java提供了一個非常有用的接口叫做Comparable,以及一個重要的方法compareTo,下面我們就來看看compareTo的具體用法吧
    2023-09-09
  • Java SPI用法案例詳解

    Java SPI用法案例詳解

    這篇文章主要介紹了Java SPI用法案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • IDEA新建的Moudle失效顯示為灰色的完美解決方案

    IDEA新建的Moudle失效顯示為灰色的完美解決方案

    這篇文章主要介紹了IDEA新建的Moudle失效顯示為灰色,本文通過圖文并茂的形式給大家分享完美解決方案,需要的朋友可以參考下
    2023-09-09

最新評論