舊數(shù)據(jù)是自增id表,如何解決MySQL分表id沖突

先來(lái)參考文章:https://mp.weixin.qq.com/s/AHRCYOjnXAgcy2j6vziukQ?tdsourcetag=s_pctim_aiomsg

方案

一般情況下,MySQL分表會(huì)有幾種方案:
1、初始點(diǎn)不同但是步數(shù)相同,比如A表起點(diǎn)是1步數(shù)是2,B表起點(diǎn)是2步數(shù)是2;
2、使用一個(gè)中間服務(wù)生成id,不再使用表自增,自己負(fù)責(zé)自增id;
3、使用UUID做id,就不怕沖突啦;
4、使用雪花算法做id,全數(shù)字還相對(duì)自增,一秒幾百萬(wàn)種可能,就不怕沖突啦。

實(shí)際上,如果系統(tǒng)是新開(kāi)發(fā),推薦你是用雪花算法,因?yàn)閡uid不能保證順序性,而第一增加運(yùn)維壓力,第二個(gè)增加開(kāi)發(fā)壓力。

問(wèn)題

問(wèn)題來(lái)咯。
如果是舊系統(tǒng),舊系統(tǒng)是自增id表,現(xiàn)在要分表怎么辦呢?

我們每個(gè)方法預(yù)演一下:
1、舊表是單表,分表必定要根據(jù)業(yè)務(wù)id取模分到各個(gè)子表里面,那么大家的起點(diǎn)就會(huì)有問(wèn)題,設(shè)置步長(zhǎng)也是會(huì)沖突。除非手動(dòng)將每個(gè)子表的maxid重新設(shè)置一個(gè)新的而且各個(gè)表的maxid是有序的,再去設(shè)置相同步長(zhǎng)。這里涉及到運(yùn)維成本!
2、新的中間服務(wù),考慮可用性必須是分布式的,考慮線(xiàn)程安全必須做騷操作,開(kāi)發(fā)成本?。?!
3、呵呵了,人家int的主鍵被你這樣一改,怕是代碼都得重寫(xiě)吧。
4、同上。

所以說(shuō):舊系統(tǒng)是自增id表,分表要么運(yùn)維成本,要么開(kāi)發(fā)成本!

我肯定選擇開(kāi)發(fā)成本,因?yàn)椴介L(zhǎng)法也有一個(gè)很大的缺點(diǎn),不能保證有序性,A子表的id大,B子表的id小,但是實(shí)際上是A子表先插入的。

解決

解決方案:
1、留下一個(gè)表,一行參數(shù)。

|max_id|
|   100|

2、寫(xiě)一個(gè)生成id的服務(wù),每次去表里面那max_id,然后虛擬出100個(gè)id在服務(wù)內(nèi)部(后面業(yè)務(wù)要用的時(shí)候分配),再把max_id設(shè)置為200。

|max_id|
|   200|

3、為了保證可用性,這個(gè)生成id的服務(wù)是分布式的,有多個(gè)。

4、然后就出現(xiàn)并發(fā)問(wèn)題了,每個(gè)服務(wù)同時(shí)取到了100,同時(shí)生成100個(gè)相同的id,同時(shí)去更新100為200.

5、解決辦法,更新的時(shí)候做手腳,如果更新條數(shù)為0就重新拿id。

6、只要實(shí)施類(lèi)似CAS樂(lè)觀鎖的思路(對(duì)比成功才替換的思路),在寫(xiě)回時(shí)對(duì)max-id的初始條件進(jìn)行比對(duì),就能避免數(shù)據(jù)的不一致,寫(xiě)回SQL由:

update T set max_id=200;
升級(jí)為:
update T set max_id=200 where max_id=100;

7、但是實(shí)際上上述是悲觀鎖,利用了mysql的排他鎖機(jī)制,update語(yǔ)句會(huì)變成兩條語(yǔ)句:

update T set max_id=200 where max_id=100;
變種為:
1、 a = select max_id from T where  max_id=100;//無(wú)鎖
2、 update T set max_id=a.max_id where max_id=100;//排他鎖
  • 先執(zhí)行第一句是無(wú)鎖的,每個(gè)服務(wù)都拿到相同的a。
  • 但是第二句是排它鎖,只能有一個(gè)請(qǐng)求執(zhí)行sql,第一個(gè)執(zhí)行之后max_id就變了,那么后續(xù)的update語(yǔ)句都會(huì)執(zhí)行條數(shù)為0.

8、如果update會(huì)自帶排他鎖,但是不能代表一定能夠保證線(xiàn)程安全,需要有技巧的使用才行的,比如:
這里改成name

update T set name =200 where max_id=100;
變種為:
1、 a = select name from T where  max_id=100;//無(wú)鎖
2、 update T set name=a.name where max_id=100;//排他鎖

大家拿到相同的a,第二條語(yǔ)句的max_id不變,就會(huì)所有線(xiàn)程都能成功執(zhí)行update語(yǔ)句?。?!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評(píng)論 19 139
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,305評(píng)論 2 89
  • CREATE TABLE IF NOT EXISTS ecs_order_info (order_id mediu...
    cookie口閱讀 16,131評(píng)論 0 16
  • 2018-08-01《六項(xiàng)精進(jìn)》第375期利他一組學(xué)員第102天打卡第411期反省一組志工寇木蘭第32天打卡 姓名...
    85fc23fc030a閱讀 179評(píng)論 0 0
  • 玻璃球,圓圓的玻璃外殼,里頭夾雜著五顏六色的花紋圖案,我們小時(shí)候總是喜歡用玻璃球彈來(lái)彈去,用球滾的距離來(lái)判定...
    喜悅璽櫟閱讀 108評(píng)論 0 0

友情鏈接更多精彩內(nèi)容