《Mysql實例MySQL中SELECT+UPDATE處理并發(fā)更新問題解決方案分享》要點:
本文介紹了Mysql實例MySQL中SELECT+UPDATE處理并發(fā)更新問題解決方案分享,希望對您有用。如果有疑問,可以聯(lián)系我們。
MYSQL應用問題背景:
MYSQL應用假設MySQL數(shù)據(jù)庫有一張會員表vip_member(InnoDB表),結構如下:
? |
MYSQL應用當一個會員想續(xù)買會員(只能續(xù)買1個月、3個月或6個月)時,必須滿足以下業(yè)務要求:
MYSQL應用?如果end_at早于當前時間,則設置start_at為當前時間,end_at為當前時間加上續(xù)買的月數(shù)
MYSQL應用?如果end_at等于或晚于當前時間,則設置end_at=end_at+續(xù)買的月數(shù)
MYSQL應用?續(xù)買后active_status必須為1(即被激活)
MYSQL應用問題分析:
MYSQL應用對于上面這種情況,我們一般會先SELECT查出這條記錄,然后根據(jù)查出記錄的end_at再UPDATE start_at和end_at,偽代碼如下(為uid是1001的會員續(xù)1個月):
MYSQL應用假如同時有兩個線程執(zhí)行上面的代碼,很顯然存在“數(shù)據(jù)覆蓋”問題(即一個是續(xù)1個月,一個續(xù)2個月,但最終可能只續(xù)了2個月,而不是加起來的3個月).
MYSQL應用解決方案:
MYSQL應用A、我想到的第一種方案是把SELECT和UPDATE合成一條SQL,如下:
MYSQL應用??? So easy!
MYSQL應用B、第二種方案:事務,即用一個事務來包裹上面的SELECT+UPDATE操作.
MYSQL應用??? 那么是否包上事務就萬事大吉了呢?
MYSQL應用??? 顯然不是.因為如果同時有兩個事務都分別SELECT到相同的vip_member記錄,那么一樣的會發(fā)生數(shù)據(jù)覆蓋問題.那有什么辦法可以解決呢?難道要設置事務隔離級別為SERIALIZABLE,考慮到性能不現(xiàn)實.
MYSQL應用??? 我們知道InnoDB支持行鎖.查看MySQL官方文檔(innodb locking reads)了解到InnoDB在讀取行數(shù)據(jù)時可以加兩種鎖:讀共享鎖和寫獨占鎖.
MYSQL應用??? 讀共享鎖是通過下面這樣的SQL獲得的:
MYSQL應用??? 如果事務A獲得了先獲得了讀共享鎖,那么事務B之后仍然可以讀取加了讀共享鎖的行數(shù)據(jù),但必須等事務A commit或者roll back之后才可以更新或者刪除加了讀共享鎖的行數(shù)據(jù).
MYSQL應用?? 如果事務A先獲得了某行的寫共享鎖,那么事務B就必須等待事務A commit或者roll back之后才可以訪問行數(shù)據(jù).
MYSQL應用?? 顯然要解決會員狀態(tài)更新問題,不能加讀共享鎖,只能加寫共享鎖,即將前面的SQL改寫成如下:
MYSQL應用??? 另外這里特別提醒下:UPDATE/DELETE SQL盡量帶上WHERE條件并在WHERE條件中設定索引過濾條件,否則會鎖表,性能可想而知有多差了.
MYSQL應用C、第三種方案:樂觀鎖,類CAS機制
MYSQL應用??? 第二種加鎖方案是一種悲觀鎖機制.而且SELECT...FOR UPDATE方式也不太常用,聯(lián)想到CAS實現(xiàn)的樂觀鎖機制,于是我想到了第三種解決方案:樂觀鎖.
MYSQL應用??? 具體來說也挺簡單,首先SELECT SQL不作任何修改,然后在UPDATE SQL的WHERE條件中加上SELECT出來的vip_memer的end_at條件.如下:
MYSQL應用??? 這樣可以根據(jù)UPDATE返回值來判斷是否更新成功,如果返回值是0則表明存在并發(fā)更新,那么只需要重試一下就好了.
MYSQL應用方案比較:
MYSQL應用三種方案各自優(yōu)劣也許眾說紛紜,只說說我自己的看法:
MYSQL應用?第一種方案利用一條比較復雜的SQL解決問題,不利于維護,因為把具體業(yè)務糅在SQL里了,以后修改業(yè)務時不但需要讀懂這條SQL,還很有可能會修改成更復雜的SQL
MYSQL應用?第二種方案寫獨占鎖,可以解決問題,但不常用
MYSQL應用?第三種方案應該是比較中庸的解決方案,并且甚至可以不加事務,也是我個人推薦的方案
MYSQL應用
此外,樂觀鎖和悲觀鎖的選擇一般是這樣的(參考了文末第二篇資料):
MYSQL應用?如果對讀的響應度要求非常高,比如證券交易系統(tǒng),那么適合用樂觀鎖,因為悲觀鎖會阻塞讀
MYSQL應用?如果讀遠多于寫,那么也適合用樂觀鎖,因為用悲觀鎖會導致大量讀被少量的寫阻塞
MYSQL應用?如果寫操作頻繁并且沖突比例很高,那么適合用悲觀寫獨占鎖
轉載請注明本頁網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/3588.html