欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ShardingJdbc讀寫分離的BUG踩坑解決

 更新時間:2022年08月29日 10:02:01   作者:女友在高考  
這篇文章主要為大家介紹了ShardingJdbc讀寫分離的BUG踩坑解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

最近公司準(zhǔn)備接入ShardingJdbc做讀寫分離了,老大讓我們理一理有沒有寫完數(shù)據(jù)立馬讀的場景,因為主從同步是有延遲的,如果寫完讀取數(shù)據(jù)走到從庫,而從庫正好有延遲,沒讀取到數(shù)據(jù),豈不是造成了生產(chǎn)事故。

今天我們來看看,ShardingJdbc作為一個成熟的框架是怎么處理寫完數(shù)據(jù)立即讀取的場景的。

數(shù)據(jù)庫介紹

我本地使用了兩個庫來做實驗,寫庫(ds_0_master)和讀庫(ds_0_salve),兩個庫并沒有配置主從,但也不影響實驗操作。

庫里有一個city 表。主庫的 city 表沒有數(shù)據(jù),而從庫的 city 表就一條數(shù)據(jù)。數(shù)據(jù)內(nèi)容如下:

我們討論 4 種業(yè)務(wù)場景:

  • 常規(guī)寫完讀
  • 在一個 service 里面調(diào)用另一個 service2 進(jìn)行讀
  • 在一個 service 里面新開一個線程去調(diào)用 service2
  • 在一個 service 里面調(diào)用 service2,但 service2 是新開的事務(wù)

先直接上實驗結(jié)果:

1. 常規(guī)寫完讀

@Service
public class CityService {
    @Autowired
    private CityRepository cityRepository;
    @Autowired
    private CityService2 cityService2;
    @Transactional(rollbackFor = Exception.class)
    public void test(){
        City city=new City();
        city.setName("眉山");
        city.setProvince("四川");
        cityRepository.save(city);
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.out.println("cityService:"+((x.getProvince().equals("四川"))?"主庫":"從庫")+":"+x);
        });
    }
}

打印結(jié)果:

實驗分析: 我們對 city 表進(jìn)行插入后,緊接著對 city 表進(jìn)行了查詢,查出的內(nèi)容是我們剛剛插入的內(nèi)容。說明查詢操作沒有走讀庫,而是走了主庫。

2. 在一個 service 里面調(diào)用另一個 service

代碼如下:

 @Transactional(rollbackFor = Exception.class)
    public void test(){
        City city=new City();
        city.setName("眉山");
        city.setProvince("四川");
        cityRepository.save(city);
        //調(diào)用其他service
        cityService2.test();
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.out.println("cityService:"+((x.getProvince().equals("四川"))?"主庫":"從庫")+":"+x);
        });
    }
}

service2 的代碼:

public void test(){
    List<City> all = cityRepository.findAll();
    all.forEach(x->{
        System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主庫":"從庫")+":"+x);
    });
}

打印結(jié)果:

實驗分析:在 service 方法里調(diào)用了其他 service,其他 service 也會受到影響。service2 也是走的主庫。

3. 新開一個線程去調(diào)用 service2

代碼如下:

@Service
public class CityService {
    @Autowired
    private CityRepository cityRepository;
    @Autowired
    private CityService2 cityService2;
    @Transactional(rollbackFor = Exception.class)
    public void test(){
        City city=new City();
        city.setName("眉山");
        city.setProvince("四川");
        cityRepository.save(city);
        new Thread(()->{cityService2.test();}).start();
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.out.println("cityService:"+((x.getProvince().equals("四川"))?"主庫":"從庫")+":"+x);
        });
    }
}
@Service
public class CityService2 {
    @Autowired
    private CityRepository cityRepository;
    public void test(){
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主庫":"從庫")+":"+x);
        });
    }
}

打印結(jié)果:

實驗分析: 我們新開了線程對 city 表進(jìn)行查詢,此次查詢讀的是從庫。新開的線程會走從庫,我猜想是新開的線程它認(rèn)為是沒有寫入/修改操作,所以走了從庫。

我又改動了 service2,加了一段寫入操作。代碼如下:

    public void test(){
        City city=new City();
        city.setName("成都");
        city.setProvince("四川");
        cityRepository.save(city);
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主庫":"從庫")+":"+x);
        });
    }

再次執(zhí)行,結(jié)果如下:

和預(yù)想的不一樣,依舊是走的從庫。

4. service2 新開一個事務(wù)執(zhí)行

我們調(diào)整 service2 的事務(wù)傳播行為級別。代碼如下:

@Transactional(propagation = Propagation.REQUIRES_NEW)
    public void test(){
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主庫":"從庫")+":"+x);
        });
    }

REQUIRES_NEW 的含義是:

強(qiáng)制自己開啟一個新的事務(wù),如果一個事務(wù)已經(jīng)存在,那么將這個事務(wù)掛起.如 ServiceA.methodA()調(diào)用 ServiceB.methodB(),methodB()上的傳播級別是 PROPAGATION_REQUIRES_NEW 的話,那么如果 methodA 報錯,不影響 methodB 的事務(wù),如果 methodB 報錯,那么 methodA 是可以選擇是回滾或者提交的,就看你是否將 methodB 報的錯誤拋出還是 try catch 了.

打印結(jié)果:

實驗分析: 這個結(jié)果確實是沒想到,service2 新開了個事務(wù)走的是主庫,而 service 里面的同一個事務(wù)里的寫后讀,反而走了從庫。

實驗總結(jié):

場景serviceservice2
同一個 service 里寫完讀主庫主庫
service 里寫完調(diào)用另一個 servcie 進(jìn)行讀操作主庫主庫
service 里寫完新開線程調(diào)用另一個 servcie 進(jìn)行讀操作主庫從庫
service 里寫完新開一個事務(wù)調(diào)用另一個 servcie 進(jìn)行讀操作從庫主庫

常規(guī)的寫完讀操作和寫完在另一個 service 里進(jìn)行讀操作,都能夠走到主庫,保證了常規(guī)業(yè)務(wù)的正確性,也滿足了我們一般的使用場景了。而新開線程進(jìn)行讀操作的情況其實比較少,如果非要使用,我們可以用強(qiáng)制指定主庫的方式進(jìn)行處理。

最后一種情況,service中調(diào)用另一個service2(新開事務(wù)),原本 service 里同一個事務(wù)的寫完讀操作走到了從庫,一不注意容易引起實際業(yè)務(wù)bug,需要使用者謹(jǐn)慎使用。大家覺得這是不是ShardingJdbc的一個BUG呢?

以上就是ShardingJdbc讀寫分離的BUG踩坑解決的詳細(xì)內(nèi)容,更多關(guān)于ShardingJdbc讀寫分離BUG的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 性能調(diào)優(yōu)之java服務(wù)器容器調(diào)優(yōu)詳解

    性能調(diào)優(yōu)之java服務(wù)器容器調(diào)優(yōu)詳解

    這篇文章主要介紹了java服務(wù)器容器調(diào)優(yōu),如果接口響應(yīng)時間超過了既定數(shù)據(jù),項目支撐不了這么大的請求,就需要對項目以及項目接口進(jìn)行數(shù)據(jù)庫、容器、緩存等方面的調(diào)優(yōu),文章中有詳細(xì)的代碼示例,需要的朋友可以參考一下
    2023-04-04
  • Spring Cloud Alibaba Nacos Config進(jìn)階使用

    Spring Cloud Alibaba Nacos Config進(jìn)階使用

    這篇文章主要介紹了Spring Cloud Alibaba Nacos Config進(jìn)階使用,文中使用企業(yè)案例,圖文并茂的展示了Nacos Config的使用,感興趣的小伙伴可以看一看
    2021-08-08
  • 解析SpringBoot @EnableAutoConfiguration的使用

    解析SpringBoot @EnableAutoConfiguration的使用

    這篇文章主要介紹了解析SpringBoot @EnableAutoConfiguration的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Spring?Boot實現(xiàn)熱部署的五種方式

    Spring?Boot實現(xiàn)熱部署的五種方式

    這篇文章主要介紹了Spring?Boot?五種熱部署方式,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • Java向數(shù)據(jù)庫插入中文出現(xiàn)亂碼解決方案

    Java向數(shù)據(jù)庫插入中文出現(xiàn)亂碼解決方案

    這篇文章主要介紹了Java向數(shù)據(jù)庫插入中文出現(xiàn)亂碼解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • 詳解Java對象創(chuàng)建的過程及內(nèi)存布局

    詳解Java對象創(chuàng)建的過程及內(nèi)存布局

    今天給大家?guī)淼奈恼率荍ava對象創(chuàng)建的過程及內(nèi)存布局,文中有非常詳細(xì)的圖文示例及介紹,需要的朋友可以參考下
    2021-06-06
  • Spring boot實現(xiàn)熱部署的兩種方式詳解

    Spring boot實現(xiàn)熱部署的兩種方式詳解

    這篇文章主要介紹了Spring boot實現(xiàn)熱部署的兩種方式,這兩種方法分別是使用 Spring Loaded和使用spring-boot-devtools進(jìn)行熱部署,文中給出了詳細(xì)示例代碼和介紹,需要的朋友可以參考學(xué)習(xí),下面來一起看看吧。
    2017-04-04
  • idea運行tomcat報錯找不到catalina.bat,系統(tǒng)找不到指定的文件問題

    idea運行tomcat報錯找不到catalina.bat,系統(tǒng)找不到指定的文件問題

    這篇文章主要介紹了idea運行tomcat報錯找不到catalina.bat,系統(tǒng)找不到指定的文件問題,具有很好的參考價值,希望對大家有所幫助,
    2023-11-11
  • SpringBoot項目docker容器部署實現(xiàn)

    SpringBoot項目docker容器部署實現(xiàn)

    本文主要介紹了SpringBoot項目docker容器部署實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • Spring創(chuàng)建Bean的6種方式詳解

    Spring創(chuàng)建Bean的6種方式詳解

    這篇文章主要介紹了Spring創(chuàng)建Bean的6種方式詳解,本文講解了在Spring 應(yīng)用中創(chuàng)建Bean的多種方式,包括自動創(chuàng)建,以及手動創(chuàng)建注入方式,實際開發(fā)中可以根據(jù)業(yè)務(wù)場景選擇合適的方案。,需要的朋友可以參考下
    2019-06-06

最新評論