最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解SpringBoot+Mybatis實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換

 更新時(shí)間:2021年05月07日 09:42:03   作者:馬小諾QAQ  
這篇文章主要介紹了詳解SpringBoot+Mybatis實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

業(yè)務(wù)背景

電商訂單項(xiàng)目分正向和逆向兩個(gè)部分:其中正向數(shù)據(jù)庫記錄了訂單的基本信息,包括訂單基本信息、訂單商品信息、優(yōu)惠卷信息、發(fā)票信息、賬期信息、結(jié)算信息、訂單備注信息、收貨人信息等;逆向數(shù)據(jù)庫主要包含了商品的退貨信息和維修信息。數(shù)據(jù)量超過500萬行就要考慮分庫分表和讀寫分離,那么我們在正向操作和逆向操作的時(shí)候,就需要動態(tài)的切換到相應(yīng)的數(shù)據(jù)庫,進(jìn)行相關(guān)的操作。

解決思路

現(xiàn)在項(xiàng)目的結(jié)構(gòu)設(shè)計(jì)基本上是基于MVC的,那么數(shù)據(jù)庫的操作集中在dao層完成,主要業(yè)務(wù)邏輯在service層處理,controller層處理請求。假設(shè)在執(zhí)行dao層代碼之前能夠?qū)?shù)據(jù)源(DataSource)換成我們想要執(zhí)行操作的數(shù)據(jù)源,那么這個(gè)問題就解決了

環(huán)境準(zhǔn)備:

1.實(shí)體類

@Data
public class Product {    
    private Integer id;    
    private String name;    
    private Double price;
}

2.ProductMapper

public interface ProductMapper { 
    @Select("select * from product") 
    public List<Product> findAllProductM(); 
    @Select("select * from product") 
    public List<Product> findAllProductS(); 
} 

3.ProductService

@Service 
public class ProductService { 
    @Autowired 
    private ProductMapper productMapper; 
    public void findAllProductM(){ 
        // 查詢Master 
        List<Product> allProductM = productMapper.findAllProductM(); 
        System.out.println(allProductM); 
    }
    public void findAllProductS(){ 
        // 查詢Slave 
        List<Product> allProductS = productMapper.findAllProductS(); 
        System.out.println(allProductS); 
    } 
}

具體實(shí)現(xiàn)

第一步:配置多數(shù)據(jù)源

首先,我們在application.properties中配置兩個(gè)數(shù)據(jù)源

spring.druid.datasource.master.password=root 
spring.druid.datasource.master.username=root 
spring.druid.datasource.master.jdbc- url=jdbc:mysql://localhost:3306/product_master? useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC 
spring.druid.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver 

spring.druid.datasource.slave.password=root 
spring.druid.datasource.slave.username=root 
spring.druid.datasource.slave.jdbc- url=jdbc:mysql://localhost:3306/product_slave? useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC 
spring.druid.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
在SpringBoot的配置代碼中,我們初始化兩個(gè)數(shù)據(jù)源:

@Configuration 
public class MyDataSourceConfiguratioin { 
    Logger logger = LoggerFactory.getLogger(MyDataSourceConfiguratioin.class); 
    /*** Master data source. */ 
    @Bean("masterDataSource") 
    @ConfigurationProperties(prefix = "spring.druid.datasource.master") 
    DataSource masterDataSource() { 
        logger.info("create master datasource..."); 
        return DataSourceBuilder.create().build(); 
    }

    /*** Slave data source. */ 
    @Bean("slaveDataSource") 
    @ConfigurationProperties(prefix = "spring.druid.datasource.slave") 
    DataSource slaveDataSource() { 
        logger.info("create slave datasource..."); 
        return DataSourceBuilder.create().build(); 
    } 

    @Bean
    @Primary
    DataSource primaryDataSource(@Autowired @Qualifier("masterDataSource")DataSource masterDataSource,

                                 @Autowired @Qualifier("masterDataSource")DataSource slaveDataSource){

        logger.info("create routing datasource..."); 
        Map<Object, Object> map = new HashMap<>(); 
        map.put("masterDataSource", masterDataSource); 
        map.put("slaveDataSource", slaveDataSource); 
        RoutingDataSource routing = new RoutingDataSource(); 
        routing.setTargetDataSources(map); 
        routing.setDefaultTargetDataSource(masterDataSource); 
        return routing; 

    }

}

第二步:編寫RoutingDataSource
然后,我們用Spring內(nèi)置的RoutingDataSource,把兩個(gè)真實(shí)的數(shù)據(jù)源代理為一個(gè)動態(tài)數(shù)據(jù)源:

public class RoutingDataSource extends AbstractRoutingDataSource { 
    @Override 
    protected Object determineCurrentLookupKey() { 
        return RoutingDataSourceContext.getDataSourceRoutingKey();
    } 
} 

第三步:編寫RoutingDataSourceContext
用于存儲當(dāng)前需要切換為哪個(gè)數(shù)據(jù)源

public class RoutingDataSourceContext { 
    // holds data source key in thread local: 
    static final ThreadLocal<String> threadLocalDataSourceKey = new ThreadLocal<>(); 
    public static String getDataSourceRoutingKey() { 
        String key = threadLocalDataSourceKey.get(); 
        return key == null ? "masterDataSource" : key; 
    }
    public RoutingDataSourceContext(String key) { 
        threadLocalDataSourceKey.set(key); 
    }
    public void close() { 
        threadLocalDataSourceKey.remove(); 
    }
}

測試(一下代碼為controller中代碼)

@GetMapping("/findAllProductM")
public String findAllProductM() {    
    String key = "masterDataSource";    
    RoutingDataSourceContext routingDataSourceContext = new RoutingDataSourceContext(key);    
    productService.findAllProductM();    
    return "master";
}
@GetMapping("/findAllProductS")
public String findAllProductS() {    
    String key = "slaveDataSource";
    RoutingDataSourceContext routingDataSourceContext = new RoutingDataSourceContext(key);
    productService.findAllProductS();
    return "slave";
}

以上代碼即可實(shí)現(xiàn)數(shù)據(jù)源動態(tài)切換

優(yōu)化:

以上代碼是可行的,但是,需要讀數(shù)據(jù)庫的地方,就需要加上一大段RoutingDataSourceContext

ctx = ...代碼,使用起來十分不便。以下是優(yōu)化方案

我們可以申明一個(gè)自定義注解,將以上RoutingDataSourceContext中的值,放在注解的value屬性中,

然后定義一個(gè)切面類,當(dāng)我們在方法上標(biāo)注自定義注解的時(shí)候,執(zhí)行切面邏輯,獲取到注解中的值,set到RoutingDataSourceContext中,從而實(shí)現(xiàn)通過注解的方式,來動態(tài)切換數(shù)據(jù)源

以下是代碼實(shí)現(xiàn):

注解類

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

切面類:

@Aspect 
@Component 
public class RoutingAspect {
 @Around("@annotation(routingWith)")
 public Object routingWithDataSource(ProceedingJoinPoint joinPoint, RoutingWith routingWith) throws Throwable {
     String key = routingWith.value();
     RoutingDataSourceContext ctx = new RoutingDataSourceContext(key);
     return joinPoint.proceed();
 }
} 

改造Controller方法

@RoutingWith("masterDataSource") 
@GetMapping("/findAllProductM") 
public String findAllProductM() {
 productService.findAllProductM(); return "lagou"; 
}

@RoutingWith("slaveDataSource") 
@GetMapping("/findAllProductS") 
public String findAllProductS() {
  productService.findAllProductS(); return "lagou";
 }

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

相關(guān)文章

  • SpringBoot快速實(shí)現(xiàn)接口消息加密的過程詳解

    SpringBoot快速實(shí)現(xiàn)接口消息加密的過程詳解

    在項(xiàng)目中,為了保證數(shù)據(jù)的安全,我們常常會對傳遞的數(shù)據(jù)進(jìn)行加密,常用的加密算法包括對稱加密(AES)和非對稱加密(RSA),博主選取碼云上最簡單的API加密項(xiàng)目進(jìn)行下面的講解,需要的朋友可以參考下
    2023-11-11
  • 基于javascript實(shí)現(xiàn)獲取最短路徑算法代碼實(shí)例

    基于javascript實(shí)現(xiàn)獲取最短路徑算法代碼實(shí)例

    這篇文章主要介紹了基于javascript實(shí)現(xiàn)獲取最短路徑算法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java中使用xls格式化xml的實(shí)例

    java中使用xls格式化xml的實(shí)例

    這篇文章主要介紹了java中調(diào)用xls格式化xml的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • Mybatis-plus多條件篩選分頁的實(shí)現(xiàn)

    Mybatis-plus多條件篩選分頁的實(shí)現(xiàn)

    本文主要介紹了Mybatis-plus多條件篩選分頁,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • SpringBoot熱部署啟動關(guān)閉流程詳解

    SpringBoot熱部署啟動關(guān)閉流程詳解

    Spring?Boot啟動熱部署是一種技術(shù),它能讓開發(fā)者在不重啟應(yīng)用程序的情況下實(shí)時(shí)更新代碼。這樣可以提高開發(fā)效率,避免頻繁重啟應(yīng)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-04-04
  • Java easyexcel導(dǎo)出報(bào)內(nèi)存溢出的問題解決

    Java easyexcel導(dǎo)出報(bào)內(nèi)存溢出的問題解決

    在Java開發(fā)時(shí),使用EasyExcel處理大數(shù)據(jù)量導(dǎo)出可能遇到內(nèi)存溢出問題,本文深入分析了內(nèi)存溢出的原因,并提出了優(yōu)化策略,感興趣的可以了解一下
    2024-10-10
  • mybatis框架之mybatis中dao層開發(fā)的兩種方法

    mybatis框架之mybatis中dao層開發(fā)的兩種方法

    這篇文章主要介紹了mybatis框架之mybatis中dao層開發(fā)的兩種方法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 淺析Java的Hibernate框架中的繼承關(guān)系設(shè)計(jì)

    淺析Java的Hibernate框架中的繼承關(guān)系設(shè)計(jì)

    這篇文章主要介紹了Java的Hibernate框架中的繼承關(guān)系設(shè)計(jì),Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • Java多線程實(shí)現(xiàn)模擬12306火車站售票系統(tǒng)

    Java多線程實(shí)現(xiàn)模擬12306火車站售票系統(tǒng)

    12360火車票售票系統(tǒng)基本上大家都用過,那你知道是怎么實(shí)現(xiàn)的嗎,今天我們就模擬12306火車站售票系統(tǒng)來實(shí)現(xiàn),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Java關(guān)于JDK1.8中的Optional類

    Java關(guān)于JDK1.8中的Optional類

    本文主要介紹了Optional類的一些常用方法,以及其應(yīng)用場景,其主要是為了規(guī)避空指針異常(NPE)。熟練的運(yùn)用Optional類可以很大的簡化我們的代碼,使代碼簡潔明了。,需要的朋友可以參考下面文章內(nèi)容
    2021-09-09

最新評論

黄梅县| 西青区| 凤阳县| 道孚县| 上蔡县| 黎平县| 诏安县| 射阳县| 南和县| 栾川县| 永清县| 闸北区| 清流县| 麻江县| 永靖县| 康定县| 务川| 黄陵县| 乳源| 新源县| 绥芬河市| 广汉市| 冀州市| 京山县| 吉木萨尔县| 奎屯市| 泌阳县| 凤城市| 龙山县| 土默特左旗| 花莲市| 库尔勒市| 永泰县| 台中县| 壶关县| 年辖:市辖区| 黑龙江省| 静乐县| 搜索| 南通市| 连州市|