<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          mybatis 多數(shù)據(jù)源動態(tài)切換

          共 2712字,需瀏覽 6分鐘

           ·

          2020-11-25 17:23

          點擊上方藍色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時間送達

          ? 作者?|??張教主

          來源 |? urlify.cn/73imQb

          66套java從入門到精通實戰(zhàn)課程分享

          筆者主要從事c#開發(fā),近期因為項目需要,搭建了一套spring-cloud微服務(wù)框架,集成了eureka服務(wù)注冊中心、
          gateway網(wǎng)關(guān)過濾、admin服務(wù)監(jiān)控、auth授權(quán)體系驗證,集成了redis、swagger、jwt、mybatis多數(shù)據(jù)源等各項功能。
          具體搭建過程后續(xù)另寫播客介紹。具體結(jié)構(gòu)如下:

          在搭建過程集成mybatis的時候,考慮到單一數(shù)據(jù)源無法滿足實際業(yè)務(wù)需要,故結(jié)合c#的開發(fā)經(jīng)驗,進行多數(shù)據(jù)源動態(tài)集成。
          mybatis的多數(shù)據(jù)源可以采用兩種方式進行,第一種是分包方式實現(xiàn),這種方式靈活性不高,而且較為繁瑣,故不做過多介紹。
          另一種方式是采用AOP的思想,進行注解動態(tài)切換,參考網(wǎng)上教程,核心思想是依靠 繼承AbstractRoutingDataSource,
          重寫determineCurrentLookupKey()方法,在該方法中使用DatabaseContextHolder獲取當(dāng)前線程的dataSource。
          但是網(wǎng)上方法大都是首先定義好各個datasource,比如有三個數(shù)據(jù)源,就需要實現(xiàn)定義好三個datasource,筆者感覺這種方法,在我
          目前這套框架中不夠靈活,因為筆者采用的是微服務(wù)框架,考慮到各個服務(wù)都有可能使用不同的數(shù)據(jù)源,而多數(shù)據(jù)源動態(tài)切換
          是放在公共方法中實現(xiàn)的,如果每有新的數(shù)據(jù)源就要定義一個,對代碼的侵入性太高,在c#中,選擇數(shù)據(jù)源很容易,根據(jù)連接名
          稱就可以切換過去,
          如下所示:


          "test1"?connectionString="server=127.0.0.1;user?id=root;password=123456;database=db1;charset=utf8"?providerName="MySql.Data.MySqlClient"?/>
          "test2"?connectionString="server=127.0.0.1;user?id=root;password=123456;database=db2;charset=utf8"?providerName="MySql.Data.MySqlClient"?/>
          "test3"?connectionString="server=127.0.0.1;user?id=root;password=123456;database=db3;charset=utf8"?providerName="MySql.Data.MySqlClient"?/>

          能不能像c#這樣根據(jù)連接名稱就自動選擇呢,筆者的連接配置如下所示:

          spring:
          ??application:
          ????name:?csg-auth
          ??datasource:
          ????kbase:
          ?????-?driverClassName:?com.kbase.jdbc.Driver
          ???????jdbcUrl:?jdbc:kbase://127.0.0.1
          ???????username:?DBOWN
          ???????password:
          ????jdbc:
          ?????-?driverClassName:?com.mysql.cj.jdbc.Driver
          ???????jdbcUrl:?jdbc:mysql://localhost:3306/nacos?serverTimezone=GMT%2B8&useUnicode=false&characterEncoding=utf8&useSSL=false
          ???????username:?root
          ???????password:?123456
          ???????connName:?nacos
          ?????-?driverClassName:?com.mysql.cj.jdbc.Driver
          ???????jdbcUrl:?jdbc:mysql://localhost:3306/tpi?serverTimezone=GMT%2B8&useUnicode=false&characterEncoding=utf8&useSSL=false
          ???????username:?root
          ???????password:?123456
          ???????connName:?tpi

          其中kbase不用理會,是我們公司自己的數(shù)據(jù)庫,jdbc是維護的連接集合,其中connName就是我們自定義的連接名稱,
          根據(jù)connName就可以自動切換到對應(yīng)數(shù)據(jù)源。

          筆者實現(xiàn)代碼如下:

          第一步

          首先,編寫DynamicDataSource類集成AbstractRoutingDataSource,重寫determineCurrentLookupKey方法,該方法主要作用是選擇數(shù)據(jù)源的key
          代碼如下:

          /**
          ?*?動態(tài)數(shù)據(jù)源
          ?*?*/
          public?class?DynamicDataSource?extends?AbstractRoutingDataSource?{
          ????@Override
          ????protected?Object?determineCurrentLookupKey()?{
          ????????return??DataSourceHolder.getDataSource();
          ????}
          }

          第二步

          第二部編寫DataSourceHolder類,提供設(shè)置、獲取、情況數(shù)據(jù)源的方法,如下所示:

          public?class?DataSourceHolder?{
          ????/**
          ?????*?線程本地環(huán)境
          ?????*/
          ????private?static?final?ThreadLocal?dataSources?=?new?ThreadLocal();

          ????/**
          ?????*?設(shè)置數(shù)據(jù)源
          ?????*/
          ????public?static?void?setDataSources(String?connName)?{
          ????????dataSources.set(connName);
          ????}

          ????/**
          ?????*?獲取數(shù)據(jù)源
          ?????*/
          ????public?static?String?getDataSource()?{
          ????????return?dataSources.get();
          ????}

          ????/**
          ?????*?清楚數(shù)據(jù)源
          ?????*/
          ????public?static?void?clearDataSource()?{
          ????????dataSources.remove();
          ????}
          }

          第三步

          第三步,編寫DataSourceConfig類,該類主要作用是讀取配置文件中的數(shù)據(jù)源連接集合,以及維護項目數(shù)據(jù)源的Bean對象,
          代碼如下:

          @Component
          @ConfigurationProperties("spring.datasource")
          public?class?DataSourceConfig?{
          ????private?List?jdbc;

          ????public?Map?getDataSourceMap(){
          ????????Mapmap=new?HashMap<>();
          ????????if?(jdbc!=null&&jdbc.size()>0){
          ????????????for?(int?i?=?0;?i?????????????????DataSourceBuilder?dataSourceBuilder=DataSourceBuilder.create();
          ????????????????dataSourceBuilder.driverClassName(jdbc.get(i).getDriverClassName());
          ????????????????dataSourceBuilder.password(jdbc.get(i).getPassword());
          ????????????????dataSourceBuilder.username(jdbc.get(i).getUsername());
          ????????????????dataSourceBuilder.url(jdbc.get(i).getJdbcUrl());
          ????????????????map.put(jdbc.get(i).getConnName(),dataSourceBuilder.build());
          ????????????}
          ????????}
          ????????return?map;
          ????}

          ????@Bean
          ????public?DataSource?csgDataSource(){
          ????????DynamicDataSource?dynamicDataSource=new?DynamicDataSource();
          ????????MapdataSourceMap=getDataSourceMap();
          ????????dynamicDataSource.setTargetDataSources(dataSourceMap);
          ?????????Object?object=?dataSourceMap.values().toArray()[0];
          ????????dynamicDataSource.setDefaultTargetDataSource(object);
          ????????return?dynamicDataSource;
          ????}

          ????public?void?setJdbc(List?jdbc)?{
          ????????this.jdbc?=?jdbc;
          ????}

          ????public?List?getJdbc(){
          ????????return?this.jdbc;
          ????}
          }

          其中,getDataSourceMap()方法,作用是根據(jù)配置的連接集合,生成AbstractRoutingDataSource所需要的resolvedDataSources。
          而csgDataSource()方法,添加了@Bean注解,作用是讓mybatis的SqlSessionFactory,能夠使用咱們維護的數(shù)據(jù)源。

          第四步

          編寫MyBatisConfig類,該類主要作用是 配置好mybatis的數(shù)據(jù)源。

          @Configuration
          public?class?MyBatisConfig?{

          ????@Autowired
          ????private?DataSource?csgDataSource;

          ????@Bean
          ????public?SqlSessionFactory?sqlSessionFactory()?throws?Exception?{
          ????????SqlSessionFactoryBean?sqlSessionFactoryBean=new?SqlSessionFactoryBean();
          ????????sqlSessionFactoryBean.setDataSource(csgDataSource);
          ????????sqlSessionFactoryBean.setMapperLocations(new?PathMatchingResourcePatternResolver()
          ????????????????.getResources("classpath:mapper/**/*.xml"));
          ????????return?sqlSessionFactoryBean.getObject();
          ????}

          ????@Bean
          ????public?PlatformTransactionManager?platformTransactionManager(){
          ????????return?new?DataSourceTransactionManager(csgDataSource);
          ????}
          }

          可以看到,這里選擇的是我們定義好的csgDataSource,其作用也是如此。

          第五步

          編寫TargetDataSource注解

          /**
          ?*?注解標(biāo)簽
          ?*?作用于?方法、接口、類、枚舉、注解
          ?*?*/

          @Retention(RetentionPolicy.RUNTIME)
          @Target({ElementType.METHOD,ElementType.TYPE})
          public?@interface?TargetDataSource?{
          ????String?connName();
          }

          其中connName,就是我們需要使用的數(shù)據(jù)源

          第六步

          編寫DataSourceExchange,改類為切面,作用于TargetDataSource注解,故使用TargetDataSource注解的時候,
          會根據(jù)connName自動選擇數(shù)據(jù)源。

          @Aspect
          @Component
          public?class?DataSourceExchange?{

          ????@Before("@annotation(TargetDataSource)")
          ????public?void?before(JoinPoint?joinPoint){
          ????????MethodSignature?sign?=?(MethodSignature)?joinPoint.getSignature();
          ????????Method?method?=?sign.getMethod();
          ????????boolean?isMethodAop=?method.isAnnotationPresent(TargetDataSource.class);
          ????????if?(isMethodAop){
          ????????????TargetDataSource?datasource?=?method.getAnnotation(TargetDataSource.class);
          ????????????DataSourceHolder.setDataSources(datasource.connName());
          ????????}else?{
          ????????????if?(joinPoint.getTarget().getClass().isAnnotationPresent(TargetDataSource.class)){
          ????????????????TargetDataSource?datasource?=?joinPoint.getTarget().getClass().getAnnotation(TargetDataSource.class);
          ????????????????DataSourceHolder.setDataSources(datasource.connName());
          ????????????}
          ????????}
          ????}

          ????@After("@annotation(TargetDataSource)")
          ????public?void?after(){
          ????????DataSourceHolder.clearDataSource();
          ????}
          }

          改切面作用于方法運行前后,負(fù)責(zé)選擇、取消數(shù)據(jù)源。

          第七步

          開始驗證,使用方法如下:

          @Service
          public?class?UserServiceImpl??implements?UserService?{
          ????@Autowired
          ????private?UserMapper?userMapper;

          ????@Override
          ????@TargetDataSource(connName?=?"nacos")
          ????public?List?getList()?{
          ????????List?list=?userMapper.selectUserList();
          ????????return?list;
          ????}
          }

          在service中,在需要進行數(shù)據(jù)庫操作的方法上,添加TargetDataSource注解,即可自動切換到所需要的數(shù)據(jù)源。
          至此,mybatis就可以動態(tài)切換數(shù)據(jù)源了。





          粉絲福利:實戰(zhàn)springboot+CAS單點登錄系統(tǒng)視頻教程免費領(lǐng)取

          ???

          ?長按上方微信二維碼?2 秒
          即可獲取資料



          感謝點贊支持下哈?

          瀏覽 69
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费草逼网站 | 日韩精品视频观看 | 五月天成人导航 | 蜜桃无码久久久久 | 99日精品|