<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近公司準備接入ShardingJdbc做讀寫分離了,老大讓我們理一理有沒有寫完資料立馬讀的場景,因為主從同步是有延遲的,如果寫完讀取資料走到從庫,而從庫正好有延遲,沒讀取到資料,豈不是造成了生產事故。
今天我們來看看,ShardingJdbc作為一個成熟的框架是怎麼處理寫完資料立即讀取的場景的。
我本地使用了兩個庫來做實驗,寫庫(ds_0_master)和讀庫(ds_0_salve),兩個庫並沒有設定主從,但也不影響實驗操作。
庫裡有一個city 表。主庫的 city 表沒有資料,而從庫的 city 表就一條資料。資料內容如下:
我們討論 4 種業務場景:
先直接上實驗結果:
@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 表進行了查詢,查出的內容是我們剛剛插入的內容。說明查詢操作沒有走讀庫,而是走了主庫。
程式碼如下:
@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 也是走的主庫。
程式碼如下:
@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); }); }
再次執行,結果如下:
和預想的不一樣,依舊是走的從庫。
我們調整 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 的含義是:
強制自己開啟一個新的事務,如果一個事務已經存在,那麼將這個事務掛起.如 ServiceA.methodA()呼叫 ServiceB.methodB(),methodB()上的傳播級別是 PROPAGATION_REQUIRES_NEW 的話,那麼如果 methodA 報錯,不影響 methodB 的事務,如果 methodB 報錯,那麼 methodA 是可以選擇是回滾或者提交的,就看你是否將 methodB 報的錯誤丟擲還是 try catch 了.
列印結果:
實驗分析: 這個結果確實是沒想到,service2 新開了個事務走的是主庫,而 service 裡面的同一個事務裡的寫後讀,反而走了從庫。
實驗總結:
場景 | service | service2 |
---|---|---|
同一個 service 裡寫完讀 | 主庫 | 主庫 |
service 裡寫完呼叫另一個 servcie 進行讀操作 | 主庫 | 主庫 |
service 裡寫完新開執行緒呼叫另一個 servcie 進行讀操作 | 主庫 | 從庫 |
service 裡寫完新開一個事務呼叫另一個 servcie 進行讀操作 | 從庫 | 主庫 |
常規的寫完讀操作和寫完在另一個 service 裡進行讀操作,都能夠走到主庫,保證了常規業務的正確性,也滿足了我們一般的使用場景了。而新開執行緒進行讀操作的情況其實比較少,如果非要使用,我們可以用強制指定主庫的方式進行處理。
最後一種情況,service中呼叫另一個service2(新開事務),原本 service 裡同一個事務的寫完讀操作走到了從庫,一不注意容易引起實際業務bug,需要使用者謹慎使用。大家覺得這是不是ShardingJdbc的一個BUG呢?
以上就是ShardingJdbc讀寫分離的BUG踩坑解決的詳細內容,更多關於ShardingJdbc讀寫分離BUG的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45