springboot+druid+mybatis plus的多數(shù)據(jù)源配置

多數(shù)據(jù)源配置流昏,在我們集成多個(gè)系統(tǒng)或者對(duì)接的時(shí)候經(jīng)常會(huì)用到冀偶,結(jié)合springboot、druid提供了比較方便的集成方案花沉。

思路:
1柳爽、yml中配置多個(gè)數(shù)據(jù)源信息
2、通過(guò)AOP切換不同數(shù)據(jù)源
3碱屁、配合mybatis plus使用


1磷脯、yml配置

spring:
  aop:
      proxy-target-class: true
      auto: true
  datasource:
    druid:
      db1:
        url: jdbc:mysql://localhost:3306/eboot
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
        initialSize: 5
        minIdle: 5
        maxActive: 20
      db2:
        url: jdbc:oracle:thin:@192.168.136.222:ORCL
        username: sa
        password: sa123456
        driver-class-name: oracle.jdbc.OracleDriver
        initialSize: 5
        minIdle: 5
        maxActive: 20
      db3:
        url: jdbc:oracle:thin:@192.168.136.223:ORCL
        username: sb
        password: sb123456
        driver-class-name: oracle.jdbc.OracleDriver
        initialSize: 5
        minIdle: 5
        maxActive: 20

2、啟動(dòng)加載多個(gè)數(shù)據(jù)源

下面mybatis plus的全局配置被注掉了娩脾,因?yàn)橥瑯涌梢栽趛ml中配置也可以

package com.df.openapi.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.MybatisConfiguration;
import com.baomidou.mybatisplus.entity.GlobalConfiguration;
import com.baomidou.mybatisplus.mapper.LogicSqlInjector;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import com.df.openapi.config.db.DBTypeEnum;
import com.df.openapi.config.db.DynamicDataSource;
import com.df.openapi.config.db.MyMetaObjectHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
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.transaction.annotation.EnableTransactionManagement;

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

/**
 * @author 小塵哥
 */
@EnableTransactionManagement
@Configuration
@MapperScan("com.df.openapi.**.mapper.db*")
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        paginationInterceptor.setLocalPage(true);
        return paginationInterceptor;
    }

    @Bean(name = "db1")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db1")
    public DataSource db1() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "db2")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db2")
    public DataSource db2() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "db3")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db3")
    public DataSource db3() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * 動(dòng)態(tài)數(shù)據(jù)源配置
     *
     * @return
     */
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("db1") DataSource db1,
                                         @Qualifier("db2") DataSource db2,
                                         @Qualifier("db3") DataSource db3) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DBTypeEnum.db1.getValue(), db1);
        targetDataSources.put(DBTypeEnum.db2.getValue(), db2);
        targetDataSources.put(DBTypeEnum.db3.getValue(), db3);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(db2);
        return dynamicDataSource;
    }

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2(),db3()));

        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        sqlSessionFactory.setConfiguration(configuration);
        //PerformanceInterceptor(),OptimisticLockerInterceptor()
        //添加分頁(yè)功能
        sqlSessionFactory.setPlugins(new Interceptor[]{
                paginationInterceptor()
        });
//        sqlSessionFactory.setGlobalConfig(globalConfiguration());
        return sqlSessionFactory.getObject();
    }

 /*   @Bean
    public GlobalConfiguration globalConfiguration() {
        GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
        conf.setLogicDeleteValue("-1");
        conf.setLogicNotDeleteValue("1");
        conf.setIdType(0);
        conf.setMetaObjectHandler(new MyMetaObjectHandler());
        conf.setDbColumnUnderline(true);
        conf.setRefresh(true);
        return conf;
    }*/
}

3赵誓、DBType枚舉類(lèi)

package com.df.openapi.config.db;

public enum DBTypeEnum {

    db1("db1"), db2("db2"), db3("db3");
    private String value;

    DBTypeEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

4、動(dòng)態(tài)數(shù)據(jù)源決策

package com.df.openapi.config.db;

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

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return  DbContextHolder.getDbType();
    }
}

5柿赊、設(shè)置俩功、獲取數(shù)據(jù)源

package com.df.openapi.config.db;

public class DbContextHolder {

    private static final ThreadLocal contextHolder = new ThreadLocal<>();
    /**
     * 設(shè)置數(shù)據(jù)源
     * @param dbTypeEnum
     */
    public static void setDbType(DBTypeEnum dbTypeEnum) {
        contextHolder.set(dbTypeEnum.getValue());
    }

    /**
     * 取得當(dāng)前數(shù)據(jù)源
     * @return
     */
    public static String getDbType() {
        return (String) contextHolder.get();
    }

    /**
     * 清除上下文數(shù)據(jù)
     */
    public static void clearDbType() {
        contextHolder.remove();
    }
}

6、AOP實(shí)現(xiàn)的數(shù)據(jù)源切換

@Order設(shè)置的足夠小是為了讓他先執(zhí)行

package com.df.openapi.config.db;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author 迪富
 */
@Component
@Order(value = -100)
@Slf4j
@Aspect
public class DataSourceSwitchAspect {

    @Pointcut("execution(* com.df.openapi.*.mapper.db1..*.*(..))")
    private void db1Aspect() {
    }

    @Pointcut("execution(* com.df.openapi.*.mapper.db2..*.*(..))")
    private void db2Aspect() {
    }

    @Pointcut("execution(* com.df.openapi.*.mapper.db3..*.*(..))")
    private void db3Aspect() {
    }

    @Before("db1Aspect()")
    public void db1() {
        log.info("切換到db1 數(shù)據(jù)源...");
        DbContextHolder.setDbType(DBTypeEnum.db1);
    }

    @Before("db2Aspect()")
    public void db2() {
        log.info("切換到db2 數(shù)據(jù)源...");
        DbContextHolder.setDbType(DBTypeEnum.db2);
    }

    @Before("db3Aspect()")
    public void db3() {
        log.info("切換到db3 數(shù)據(jù)源...");
        DbContextHolder.setDbType(DBTypeEnum.db3);
    }
}

7碰声、mapper層結(jié)構(gòu)

根據(jù)dbx的實(shí)現(xiàn)數(shù)據(jù)源切換.png

8绑雄、寫(xiě)一個(gè)service測(cè)試一下

可以看到下面的兩個(gè)Mapper分別來(lái)自db1和db2

package com.df.openapi.system.service.impl;

import com.df.openapi.system.entity.PtDict;
import com.df.openapi.system.entity.SysDict;
import com.df.openapi.system.mapper.db1.PtDictMapper;
import com.df.openapi.system.mapper.db2.SysDictMapper;
import com.df.openapi.system.service.IDictService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class DictServiceImpl implements IDictService {

    @Resource
    private PtDictMapper ptDictMapper;

    @Resource
    private SysDictMapper sysDictMapper;


    @Override
    public void getById(String id) {
        PtDict dict = ptDictMapper.selectById("2bf6257fc8fe483c84c1ad7e89d632f6");
        SysDict sysDict = sysDictMapper.getById("49");
        System.out.println("123");
    }
}

9、簡(jiǎn)單的單元測(cè)試

@RunWith(SpringRunner.class)
@SpringBootTest
public class OpenApiApplicationTests {

    @Autowired
    private IDictService dictService;

    @Test
    public void contextLoads() {
    }

    @Test
    public void test() {
        dictService.getById("1");
    }
}

10奥邮、測(cè)試結(jié)果

取到兩個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù).png

參考上面的方法万牺,可以隨意配置三四五六七八九十個(gè)數(shù)據(jù)源都沒(méi)問(wèn)題,有問(wèn)題歡迎隨時(shí)來(lái)撩洽腺!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脚粟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蘸朋,更是在濱河造成了極大的恐慌核无,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藕坯,死亡現(xiàn)場(chǎng)離奇詭異团南,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)炼彪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)吐根,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人辐马,你說(shuō)我怎么就攤上這事拷橘。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵冗疮,是天一觀(guān)的道長(zhǎng)萄唇。 經(jīng)常有香客問(wèn)我,道長(zhǎng)术幔,這世上最難降的妖魔是什么另萤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮诅挑,結(jié)果婚禮上仲墨,老公的妹妹穿的比我還像新娘。我一直安慰自己揍障,他們只是感情好目养,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著毒嫡,像睡著了一般癌蚁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兜畸,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天努释,我揣著相機(jī)與錄音,去河邊找鬼咬摇。 笑死伐蒂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肛鹏。 我是一名探鬼主播逸邦,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼在扰!你這毒婦竟也來(lái)了缕减?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤芒珠,失蹤者是張志新(化名)和其女友劉穎桥狡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體皱卓,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裹芝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娜汁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫂易。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖存炮,靈堂內(nèi)的尸體忽然破棺而出炬搭,到底是詐尸還是另有隱情,我是刑警寧澤穆桂,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布宫盔,位于F島的核電站,受9級(jí)特大地震影響享完,放射性物質(zhì)發(fā)生泄漏灼芭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一般又、第九天 我趴在偏房一處隱蔽的房頂上張望彼绷。 院中可真熱鬧,春花似錦茴迁、人聲如沸寄悯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)猜旬。三九已至,卻和暖如春倦卖,著一層夾襖步出監(jiān)牢的瞬間洒擦,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工怕膛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留熟嫩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓褐捻,卻偏偏與公主長(zhǎng)得像掸茅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子柠逞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理倦蚪,服務(wù)發(fā)現(xiàn),斷路器边苹,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 嘟嘟媽親子閱讀打卡436天个束! 廖單踐行第三周第六慕购,一早上聽(tīng)了會(huì),下午配合書(shū)聽(tīng)《go away mr. wolf》和...
    霍嘟嘟媽媽閱讀 186評(píng)論 0 0
  • 冥冥之中茬底,一方布滿(mǎn)迷霧沪悲、無(wú)天無(wú)地、無(wú)味無(wú)色的封閉空間阱表,孤寂凄冷而荒涼殿如。 這里是六道輪回中贡珊,地獄道演化的萬(wàn)千地獄中的...
    銀劍書(shū)生閱讀 644評(píng)論 0 0
  • 老是覺(jué)得自己和別人交談總會(huì)提到一個(gè)梗,那就是自己小時(shí)候的世界觀(guān)涉馁,不知道是出于懷念還是出于幽默门岔,或者出于其他。 那時(shí)...
    矯揉做作狂閱讀 198評(píng)論 0 0