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

ShardingJdbc讀寫分離的BUG踩坑解決

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

前言

最近公司準備接入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ù)內容如下:

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

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

先直接上實驗結果:

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);
        });
    }
}

打印結果:

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

2. 在一個 service 里面調用另一個 service

代碼如下:

 @Transactional(rollbackFor = Exception.class)
    public void test(){
        City city=new City();
        city.setName("眉山");
        city.setProvince("四川");
        cityRepository.save(city);
        //調用其他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);
    });
}

打印結果:

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

3. 新開一個線程去調用 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);
        });
    }
}

打印結果:

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

我又改動了 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í)行,結果如下:

和預想的不一樣,依舊是走的從庫。

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

我們調整 service2 的事務傳播行為級別。代碼如下:

@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 的含義是:

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

打印結果:

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

實驗總結:

場景serviceservice2
同一個 service 里寫完讀主庫主庫
service 里寫完調用另一個 servcie 進行讀操作主庫主庫
service 里寫完新開線程調用另一個 servcie 進行讀操作主庫從庫
service 里寫完新開一個事務調用另一個 servcie 進行讀操作從庫主庫

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

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

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

相關文章

  • 迅速掌握Java容器中常用的ArrayList類與Vector類用法

    迅速掌握Java容器中常用的ArrayList類與Vector類用法

    這篇文章主要介紹了Java容器中常用的ArrayList類與Vector類用法,文中只對其最基本的功能給出了示例代碼,需要的朋友可以參考下
    2015-11-11
  • SpringMVC使用@Valid注解實現(xiàn)數(shù)據(jù)驗證的代碼示例

    SpringMVC使用@Valid注解實現(xiàn)數(shù)據(jù)驗證的代碼示例

    在 Web 開發(fā)中,數(shù)據(jù)驗證是一個非常重要的環(huán)節(jié),它可以確保數(shù)據(jù)的合法性和正確性,保護系統(tǒng)不受到惡意攻擊或用戶誤操作的影響,在 SpringMVC 中,我們可以使用 @Valid 注解來實現(xiàn)數(shù)據(jù)驗證,所以本文就給大家介紹具體的使用方法,需要的朋友可以參考下
    2023-07-07
  • Java創(chuàng)建型設計模式之建造者模式詳解

    Java創(chuàng)建型設計模式之建造者模式詳解

    建造者模式是Java中一種創(chuàng)建型設計模式,它的主要目的是將一個復雜對象的構建過程分解為多個簡單對象的構建過程,本文將詳細介紹Java中的建造者模式,包括它的定義、結構、實現(xiàn)方法以及應用場景等方面,希望對大家有所幫助
    2023-05-05
  • java線程之Happens before規(guī)則案例詳解

    java線程之Happens before規(guī)則案例詳解

    這篇文章主要為大家介紹了java線程之Happens-before規(guī)則,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>
    2022-08-08
  • Spring AOP里的靜態(tài)代理和動態(tài)代理用法詳解

    Spring AOP里的靜態(tài)代理和動態(tài)代理用法詳解

    這篇文章主要介紹了 Spring AOP里的靜態(tài)代理和動態(tài)代理用法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • Java實現(xiàn)讀取Word模板文檔并替換內容生成新文檔

    Java實現(xiàn)讀取Word模板文檔并替換內容生成新文檔

    在實際開發(fā)中,經(jīng)常會遇到需要根據(jù) Word 模板生成特定文檔的需求,下面小編就來為大家介紹一下如何使用 Apache POI 庫來讀取 Word 模板文檔,然后替換其中的指定內容最后生成新的文檔吧
    2025-02-02
  • Spring?Boot詳解五種實現(xiàn)跨域的方式

    Spring?Boot詳解五種實現(xiàn)跨域的方式

    跨域指的是瀏覽器不能執(zhí)?其他?站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對javascript施加的安全限制,這篇文章主要介紹了springboot實現(xiàn)跨域的5種方式,需要的朋友可以參考下
    2022-06-06
  • Java項目中防止SQL注入的四種方法推薦

    Java項目中防止SQL注入的四種方法推薦

    sql注入是web開發(fā)中最常見的一種安全漏洞,這篇文章為大家整理了四種Java項目中防止SQL注入的方法,有需要的小伙伴可以參考一下
    2025-03-03
  • Maven配置中repositories、distributionManagement、pluginRepositories用法及將已有jar包部署到私服

    Maven配置中repositories、distributionManagement、pluginRepositori

    這篇文章主要介紹了Maven配置中repositories、distributionManagement、pluginRepositories用法及將已有jar包部署到私服,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Java中JWT令牌實現(xiàn)登錄驗證

    Java中JWT令牌實現(xiàn)登錄驗證

    本文主要介紹了JWT令牌在Java中實現(xiàn)登錄驗證的方法,JWT是一種自我包含的、無狀態(tài)的認證機制,可以用來在客戶端和服務器之間傳遞安全可靠的信息,感興趣的可以了解一下
    2024-12-12

最新評論

赣州市| 靖远县| 门头沟区| 承德市| 莱芜市| 宾阳县| 福清市| 花莲市| 清苑县| 镇雄县| 会泽县| 陆丰市| 滦平县| 正阳县| 永登县| 民县| 高淳县| 蕲春县| 张北县| 从化市| 安国市| 启东市| 广南县| 邯郸市| 内黄县| 琼结县| 无极县| 南城县| 龙州县| 台山市| 曲阜市| 九江县| 宁陕县| 兴文县| 黑山县| 翁源县| 梅河口市| 宜春市| 外汇| 本溪市| 广宗县|