SpringBoot Mybatis 多數據源配置 注解方式切換數據源

SpringBoot Mybatis 多數據源配置 注解方式切換數據源

整合了下網上找到的各種方法,終于ojbk,Mark下,以免下次再次遇到

介紹

近期因項目需求,原有的SpringBoot項目需要連接到兩個數據庫獲取數據,確定有如下方案:

  • DBLink -- 此方式適合同時兩個oracle數據庫,連接其中一個數據庫,通過DBLink可以獲取到另一個數據庫的數據,但是這種方式只能在兩個oracle數據庫間使用,適用性不強,pass
  • 數據同步 -- 通過原有的數據庫同步軟件進行同步,這種方式可以支持在兩個非oracle數據庫間使用,但是同步資源消耗,對于實時性要求較大的數據不適用,pass
  • 如題,通過SpringBoot+Mybatis多數據源配置實現多數據源連接,采用注解方式,支持任意數據庫,默認使用原數據庫,原有代碼無需變更,下邊將詳細介紹這種方式的配置方法。

項目結構

image.png

多數據源配置

Application新增注解,排除DataSourceAutoConfiguration,手動配置數據源

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

修改application.properties數據庫配置

#db1數據庫配置
db1.datasource.url = url
db1.datasource.username = username
db1.datasource.password = password
db1.datasource.driver-class-name=oracle.jdbc.OracleDriver

#db2數據庫配置
db2.datasource.url = url
db2.datasource.username = username
db2.datasource.password = password
db2.datasource.driver-class-name=oracle.jdbc.OracleDriver

DataSourceConfig讀取數據庫配置,手動配置數據源

import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DataSourceConfig {
    /**
     * db1數據庫配置
     */
    @Bean("db1")
    @ConfigurationProperties(prefix = "db1.datasource")
    public DataSource db1Source() {
        return DataSourceBuilder.create().build();
    }

    /**
     * db2數據庫配置
     */
    @Bean("db2")
    @ConfigurationProperties(prefix = "db2.datasource")
    public DataSource db2Source() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 動態數據庫配置
     */
    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 默認數據源
        dynamicDataSource.setDefaultTargetDataSource(db1Source());

        // 配置多數據源
        Map<Object, Object> dsMap = new HashMap(5);
        dsMap.put("db1", db1Source());
        dsMap.put("db2", db2Source());

        dynamicDataSource.setTargetDataSources(dsMap);

        return dynamicDataSource;
    }

    /**
     * 配置@Transactional注解事物
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }

}

配置DataSourceContextHolder上下文

public class DataSourceContextHolder {
    // 默認數據源
    public static final String DEFAULT_DS = "db1";

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

    public static void setDB(String dbType) {
        contextHolder.set(dbType);
    }

    public static String getDB() {
        return (contextHolder.get());
    }

    public static void clearDB() {
        contextHolder.remove();
    }
}

動態數據源

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

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDB();
    }
}

注解方式配置

自定義注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataBase {
    String value() default "db1";
}

切面

import com.xxx.common.annotation.DataBase;
import com.xxx.common.config.DataSourceContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class DataBaseAspect {

    @Pointcut("@annotation(com.xxx.common.annotation.DataBase)")
    public void dbPointCut() {

    }

    @Before("dbPointCut()")
    public void beforeSwitchDS(JoinPoint point){
        //獲得當前訪問的class
        Class<?> className = point.getTarget().getClass();
        //獲得訪問的方法名
        String methodName = point.getSignature().getName();
        //得到方法的參數的類型
        Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();

        String dataSource = DataSourceContextHolder.DEFAULT_DS;
        try {
            // 得到訪問的方法對象
            Method method = className.getMethod(methodName, argClass);

            // 判斷是否存在@DateBase注解
            if (method.isAnnotationPresent(DataBase.class)) {
                DataBase annotation = method.getAnnotation(DataBase.class);
                // 取出注解中的數據源名
                dataSource = annotation.value();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 切換數據源
        DataSourceContextHolder.setDB(dataSource);
    }

    @After("dbPointCut()")
    public void afterSwitchDS(JoinPoint point){
        DataSourceContextHolder.clearDB();
    }
}

項目中調用

至此,SpringBoot + MyBaties 多數據源配置完成。使用時,在service層方法上調用@DataBase注解,無注解時,使用默認數據源。

    //默認(第一)數據源
    public void test(){
      return;
    }

    //默認(第一)數據源
    @DataBase("db1")
    public void test(){
      return;
    }

    //第二數據源
    @DataBase("db2")
    public void test(){
      return;
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景: 閱讀新聞 12C CDB模式下RMAN備份與恢復 [日期:2016-11-29] 來源:Linux社區 作...
    陽屯okyepd閱讀 3,559評論 0 7
  • 1、引言 數據庫設計過程中表、字段等的命名規范也算是設計規范的一部分,不過設計規范更多的是為了確保數據庫設計的合理...
    SnowflakeCloud閱讀 41,070評論 0 48
  • 桃花運勢對戀愛相當重要,薇時也幫助很多女生找到了心儀對象,今天就把這些方法都分享出來,希望可以幫到更多的人噢。 一...
    薇時閱讀 416評論 0 0
  • 一個人,漫無目的地走在人行道上,蔥蘢的綠化樹,還是一如盛夏時的蒼翠欲滴,南方的秋,沒太多秋的痕跡。只是偶爾看到一片...
    一泓夜雨閱讀 280評論 4 9
  • 我在適合郊游的天氣,來到北京。 度過炎熱的夏天,享受舒服的秋天,現在,迎來了寒風刺骨的冬天。 還差一個明媚的春天。...
    DARK_CHOCOLATE閱讀 337評論 2 0