• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看

      ?

      基于Spring Boot與MyBatis框架構(gòu)建動(dòng)態(tài)讀寫分離模型

      2021-03-17 07:32:48張旭剛張昕高若寒
      微型電腦應(yīng)用 2021年2期
      關(guān)鍵詞:數(shù)據(jù)源線程調(diào)用

      張旭剛, 張昕, 高若寒

      (國電南瑞科技股份有限公司 信息系統(tǒng)集成分公司, 江蘇 南京 210000)

      0 引言

      讀寫分離集群,不僅提高了系統(tǒng)的健壯性和可靠性,以及系統(tǒng)的吞吐量和性能,保障了系統(tǒng)業(yè)務(wù)的連續(xù)性,而且也實(shí)現(xiàn)了資源的最大利用率。當(dāng)前的實(shí)現(xiàn)方法主要通過靜態(tài)方式配置,主要有中間件方式,如amoeba和mysql-proxy,分業(yè)務(wù)方式,對(duì)讀寫操作配置url。靜態(tài)方式缺乏靈活性,無法根據(jù)系統(tǒng)負(fù)載、用戶需求等情況,實(shí)現(xiàn)資源的快速動(dòng)態(tài)收縮,難以滿足在不停機(jī)的條件下進(jìn)行數(shù)據(jù)源切換,無法保證業(yè)務(wù)的連續(xù)性。

      利用Spring Boot和MyBatis框架提供的優(yōu)勢(shì),通過面向切面編程AOP,實(shí)現(xiàn)一種對(duì)應(yīng)用透明、數(shù)據(jù)源可以動(dòng)態(tài)收縮與切換的模型。

      1 Spring Boot架構(gòu)

      Spring Boot是由Pivotal團(tuán)隊(duì)提供,簡化Spring開發(fā)的微服務(wù)框架。通過約定優(yōu)于配置和起步依賴,簡化復(fù)雜的依賴關(guān)系,大量減少XML配置文件,基本實(shí)現(xiàn)自動(dòng)化位置,能夠快速創(chuàng)建獨(dú)立運(yùn)行的Spring項(xiàng)目,并且集成了主流框架,如AOP和MyBatis。為實(shí)現(xiàn)動(dòng)態(tài)讀寫分離模型,主要利用面向切面編程技術(shù)AOP、MyBatis映射、SpringBoot的類Abstract Routing Data Source和Thread Local實(shí)現(xiàn)不同線程間的數(shù)據(jù)隔離[1]。

      1.1 Spring AOP

      Spring AOP(Aspect-Oriented Programming,面向切面編程),是一種稱為“橫切”的技術(shù),把與業(yè)務(wù)無關(guān)邏輯,但為業(yè)務(wù)模塊共同調(diào)用的邏輯或功能封裝起來,將其命名為“Aspect”,即方面,減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,便于后期的操作和維護(hù)。在論文中,主要使用AOP的前置通知,攔截MyBatis映射的SQL語句,動(dòng)態(tài)選擇數(shù)據(jù)源。

      1.2 MyBatis映射

      Mybatis是一個(gè)支持普通SQL查詢、存儲(chǔ)過程和高級(jí)映射的優(yōu)秀持久層框架,在持久層映射關(guān)系的開發(fā)中,可以不用寫實(shí)現(xiàn)類,能以代理方式自動(dòng)生成實(shí)現(xiàn)代碼,同時(shí)SQL語句寫在映射XML文件中,實(shí)現(xiàn)了代碼與SQL分離,降低耦合度。在映射XML文件中,通過id標(biāo)識(shí)不同類型的SQL語句,對(duì)查詢、插入、刪除和更新語句進(jìn)行區(qū)分,如查詢語句的id前綴為query,刪除語句的id前綴為delete,通過甄別判斷為不同SQL語句選擇對(duì)應(yīng)的數(shù)據(jù)源,實(shí)現(xiàn)動(dòng)態(tài)的讀寫分離。

      1.3 Abstract Routing Data Source

      Spring Boot提供了Abstract Routing Data Source根據(jù)用戶定義的規(guī)則選擇當(dāng)前的數(shù)據(jù)源,可以在執(zhí)行SQL操作前,設(shè)置使用的數(shù)據(jù)源,實(shí)現(xiàn)動(dòng)態(tài)路由數(shù)據(jù)源的模型,它的方法determine Target Data Source()返回一個(gè)數(shù)據(jù)源,在該方法內(nèi)部會(huì)調(diào)用抽象方法determine Current Lookup Key()決定使用哪個(gè)數(shù)據(jù)源,lookup key鍵通常是通過Thread Local綁定的上下文來實(shí)現(xiàn)。

      1.4 Thread Local

      Thread Local作用是提供線程內(nèi)的局部變量,維護(hù)變量時(shí)Thread Local為每個(gè)使用該變量的線程提供獨(dú)立的變量副本。

      在面向切面編程AOP的前置通知中通過Thread Local設(shè)置線程的數(shù)據(jù)源類型,是讀數(shù)據(jù)源還是寫數(shù)據(jù)源。在返回?cái)?shù)據(jù)源的時(shí)候,通過determine Current Lookup Key()調(diào)用Thread Local取得線程的數(shù)據(jù)源類型,從而為本次訪問指定具體的數(shù)據(jù)源,是訪問讀庫還是寫庫[2]。

      2 動(dòng)態(tài)讀寫分離設(shè)計(jì)與實(shí)現(xiàn)

      2.1 總體架構(gòu)

      程序?qū)崿F(xiàn)基于Spring Boot框架,通過Maven進(jìn)行編譯、測試和打包。Spring Boot基于Spring,減少了配置,簡化了編碼,使開發(fā)更高效便捷[3]。整體實(shí)現(xiàn)分五層,第一層客戶端即應(yīng)用程序,發(fā)起數(shù)據(jù)訪問;第二層訪問到DAO(數(shù)據(jù)訪問對(duì)象),訪問的sql語句配置在MyBatis的映射文件里,與程序的DAO接口形成映射關(guān)系,由MyBatis自動(dòng)實(shí)現(xiàn)接口的文件,對(duì)數(shù)據(jù)庫進(jìn)行訪問;第三層,AOP,即面向切面編程層,在DAO訪問數(shù)據(jù)庫之前,進(jìn)行攔截,根據(jù)訪問id進(jìn)行動(dòng)態(tài)選擇數(shù)據(jù)源,如果是查詢語句則訪問讀庫,如果是修改語句,則指向到主數(shù)據(jù)庫,實(shí)現(xiàn)數(shù)據(jù)的讀寫分離,主要功能有負(fù)載均衡、高可用性、SQL過濾、讀寫分離和數(shù)據(jù)庫路由等;第四層,創(chuàng)建和封裝兩個(gè)數(shù)據(jù)源,每個(gè)數(shù)據(jù)源創(chuàng)建一個(gè)數(shù)據(jù)庫資源池,分別指向?qū)憯?shù)據(jù)庫和讀數(shù)據(jù)庫;第五層,主備數(shù)據(jù)庫之間,通過binlog進(jìn)行數(shù)據(jù)實(shí)時(shí)同步,并進(jìn)行故障切換[4]。

      通過上面五層,與Spring Boot和MyBatis架構(gòu)構(gòu)建程序一致,對(duì)原有程序透明,無任何侵入,原程序不需要任何改造,簡單便捷地實(shí)現(xiàn)了動(dòng)態(tài)的數(shù)據(jù)庫讀寫分離[5]。

      同時(shí),這種結(jié)構(gòu)可以進(jìn)行橫向擴(kuò)展,當(dāng)性能無法滿足需求時(shí),添加數(shù)據(jù)源,添加數(shù)據(jù)庫,進(jìn)行負(fù)載分擔(dān),對(duì)應(yīng)用透明,如圖1所示。

      2.2 讀寫分離的實(shí)現(xiàn)

      實(shí)現(xiàn)MySQL數(shù)據(jù)庫的動(dòng)態(tài)讀寫分離,讀寫分離的實(shí)現(xiàn)類圖,如圖2所示。

      主要由四個(gè)類實(shí)現(xiàn),Dynamic Data Source動(dòng)態(tài)的根據(jù)數(shù)據(jù)源的值返回?cái)?shù)據(jù)源;Data Source Context Holder封裝了Thread Local,用于設(shè)置和獲取本次訪問的數(shù)據(jù)源的值;Dynamic Data Source Aspect實(shí)現(xiàn)AOP的前置通知,攔截和解析SQL的id,根據(jù)id判斷是讀操作還是寫操作,通過Data Source Context Holder動(dòng)態(tài)設(shè)置數(shù)據(jù)源的值,然后Dynamic Data Source獲取到要訪問的數(shù)據(jù)源;Multi Data Source Con-fig配置多個(gè)數(shù)據(jù)源,在應(yīng)用啟動(dòng)后有多個(gè)數(shù)據(jù)源可以選擇。

      圖1 總體結(jié)構(gòu)圖

      圖2 讀寫分離的實(shí)現(xiàn)類圖

      Dynamic Data Source,用于獲取數(shù)據(jù)庫訪問的數(shù)據(jù)源,如果是查詢操作,返回只讀庫數(shù)據(jù)源,如果是增刪改則訪問寫庫。繼承Abstract Routing Data Source并重寫其中的方法determine Current Lookup Key(),該方法調(diào)用封裝了Thread Local的Database Context Holder,獲取當(dāng)前線程的Database Type。

      Data Source Context Holder,用戶設(shè)置數(shù)據(jù)庫訪問的數(shù)據(jù)源,具體設(shè)置通過切面攔截調(diào)用該類的方法set Data Source Type。該類擁有一個(gè)Thread Local的靜態(tài)常量私有屬性private static final Thread Local〈String〉 CONTEXT_HOLDER = new Thread Local〈String〉(),靜態(tài)方法set Data Source Type(String data Source Key)和get Data Source Type()通過CONTEXT_HOLDER屬性,用于標(biāo)識(shí)數(shù)據(jù)源,給每個(gè)訪問數(shù)據(jù)庫的線程返回要訪問的數(shù)據(jù)源。

      Dynamic Data Source Aspect用于定義要攔截的SQL操作,通過前置通知解析MyBatis中配置的id,根據(jù)id判斷SQL操作是讀操作還是增刪改,并利用Data Source Context Holder的靜態(tài)方法設(shè)置當(dāng)前線程的數(shù)據(jù)源類型。在進(jìn)行數(shù)據(jù)源選擇時(shí),Dynamic Data Source返回設(shè)置的當(dāng)前線程的數(shù)據(jù)源類型,當(dāng)前線程準(zhǔn)確地找到需要訪問的數(shù)據(jù)源。它的主要實(shí)現(xiàn)方法如下。

      @Pointcut("execution( * com.sboot.dao.*.*(..))")

      public void daoAspect() {

      }

      @Before("daoAspect()")

      public void switchDataSource(JoinPoint point) {

      System.out.println("Begin to execute "+point.getSignature().getName());

      Boolean isQueryMethod = isQueryMethod(point.getSignature().getName());

      if (isQueryMethod) {

      DataSourceContextHolder.setDataSourceType("slave");

      System.out.println("Slave DataSource begin to execute "+point.getSignature().getName());

      }

      }

      Multi Data Source Config,是一個(gè)基于注解的配置,主要封裝了寫和讀兩個(gè)數(shù)據(jù)源,實(shí)現(xiàn)多數(shù)據(jù)源,需要取消Spring Boot的自動(dòng)數(shù)據(jù)源配置,主要實(shí)現(xiàn)方法如下。

      @Bean("dynamicDataSource")

      public DataSource dynamicDataSource() {

      Map〈Object, Object〉 targetDataSources = new HashMap〈Object, Object〉();

      targetDataSources.put("master", masterDataSource());

      targetDataSources.put("slave", slaveDataSource());

      DynamicDataSource dataSource = new DynamicDataSource();

      dataSource.setTargetDataSources(targetDataSources);

      dataSource.setDefaultTargetDataSource(masterDataSource());

      return dataSource;

      }

      2.3 配置多數(shù)據(jù)源

      在application.yml中添加兩個(gè)數(shù)據(jù)源[6]:

      pring:

      datasource:

      master://寫數(shù)據(jù)源的配置

      url:

      jdbc:mysql://192.168.10.12:3306/masterdb?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true

      username: studba

      password: stuDba1

      driverClassName: com.mysql.cj.jdbc.Driver

      slave://讀數(shù)據(jù)源的配置

      url:

      jdbc:mysql://192.168.10.13:3306/slavedb?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true

      username: studba

      password: stuDba1

      driverClassName: com.mysql.cj.jdbc.Driver

      然后在類DataSourceConfig中,利用注解的方式生成數(shù)據(jù)源:

      @Primary

      @Bean("masterDataSource")

      @ConfigurationProperties(prefix = "spring.datasource.master")

      public DataSource masterDataSource() {

      return DataSourceBuilder.create().build();

      }

      通過@ConfigurationProperties注解把在配置文件的配置自動(dòng)的匹配配置數(shù)據(jù)源需要的值,生成數(shù)據(jù)源。備數(shù)據(jù)源的原理與上面一致。

      2.4 數(shù)據(jù)訪問流程

      數(shù)據(jù)訪問流程,如圖3所示。

      圖3 數(shù)據(jù)訪問流程

      (1) 客戶端訪問數(shù)據(jù)庫,正常流程走到DAO層,MyBatis進(jìn)行映射接口,取得映射的sql語句,如findStudentById。

      (2) 取得sql語句訪問數(shù)據(jù)庫。

      (3) 通過@Before("daoAspect()")攔截訪問,并檢查是查詢語句,設(shè)置數(shù)據(jù)源為讀數(shù)據(jù)庫。

      判斷出是find開頭的sql語句,設(shè)置讀數(shù)據(jù)源DataSourceContextHolder.setDataSourceType("slave")。

      (4) MultiDynamicDataSource

      在方法determineCurrentLookupKey()中返回?cái)?shù)據(jù)源類型return DataSourceContextHolder.getDataSourceType()。

      (5) MultiDynamicDataSource的方法

      determineTargetDataSource()根據(jù)上面determineCurrentLookupKey()函數(shù)返回的key值選擇一個(gè)指定的數(shù)據(jù)源。

      (6) 返回要訪問的數(shù)據(jù)源,本次訪問返回的是讀數(shù)據(jù)源。

      (7) 根據(jù)返回的讀數(shù)據(jù)源,訪問讀數(shù)據(jù)庫。

      2.5 應(yīng)用驗(yàn)證

      通過學(xué)生ID查詢學(xué)生信息進(jìn)行驗(yàn)證,查詢操作到讀庫進(jìn)行操作。查詢學(xué)生信息的MyBatis SQL id是findStudent ById,在瀏覽器輸入http://192.168.1.10:8080/stuInfo,進(jìn)行查詢,日志輸出信息,如圖4所示。

      圖4 測試驗(yàn)證

      日志打印出執(zhí)行sql語句findStudentById,動(dòng)態(tài)選擇讀數(shù)據(jù)源Slave DataSource執(zhí)行。

      3 總結(jié)

      本文基于Spring Boot和MyBatis框架,實(shí)現(xiàn)了動(dòng)態(tài)的MySQL讀寫分離模型,方法簡單、便捷,對(duì)應(yīng)用透明,低耦合,無侵入性,安裝和拆卸對(duì)現(xiàn)有程序無任何影響,沒有額外的成本。后續(xù)可加入多數(shù)據(jù)源,通過zookeeper進(jìn)行狀態(tài)監(jiān)控和管理,實(shí)現(xiàn)更智能和動(dòng)態(tài)的數(shù)據(jù)庫的橫向擴(kuò)展和收縮,滿足云計(jì)算場景需求。

      猜你喜歡
      數(shù)據(jù)源線程調(diào)用
      核電項(xiàng)目物項(xiàng)調(diào)用管理的應(yīng)用研究
      LabWindows/CVI下基于ActiveX技術(shù)的Excel調(diào)用
      Web 大數(shù)據(jù)系統(tǒng)數(shù)據(jù)源選擇*
      基于不同網(wǎng)絡(luò)數(shù)據(jù)源的期刊評(píng)價(jià)研究
      淺談linux多線程協(xié)作
      基于系統(tǒng)調(diào)用的惡意軟件檢測技術(shù)研究
      基于真值發(fā)現(xiàn)的沖突數(shù)據(jù)源質(zhì)量評(píng)價(jià)算法
      分布式異構(gòu)數(shù)據(jù)源標(biāo)準(zhǔn)化查詢?cè)O(shè)計(jì)與實(shí)現(xiàn)
      利用RFC技術(shù)實(shí)現(xiàn)SAP系統(tǒng)接口通信
      Linux線程實(shí)現(xiàn)技術(shù)研究
      曲周县| 谷城县| 湖州市| 抚州市| 龙陵县| 巩留县| 页游| 星子县| 自治县| 呼玛县| 揭西县| 集安市| 措勤县| 泽库县| 东乌珠穆沁旗| 宽甸| 锡林浩特市| 岳普湖县| 时尚| 来安县| 缙云县| 肇州县| 龙井市| 衡山县| 惠水县| 余庆县| 夹江县| 三门县| 交城县| 兰溪市| 灵丘县| 新密市| 兴宁市| 枝江市| 和顺县| 六盘水市| 东兰县| 安丘市| 阜新| 阿拉善右旗| 隆尧县|