久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

MySQL中SELECT+UPDATE處理并發(fā)更新問題解決方案

瀏覽:8日期:2023-10-17 08:07:13

這篇文章主要介紹了MySQL中SELECT+UPDATE處理并發(fā)更新問題解決方案分享,需要的朋友可以參考下。

問題背景

假設(shè)MySQL數(shù)據(jù)庫有一張會員表vip_member(InnoDB表),結(jié)構(gòu)如下:

MySQL中SELECT+UPDATE處理并發(fā)更新問題解決方案

當一個會員想續(xù)買會員(只能續(xù)買1個月、3個月或6個月)時,必須滿足以下業(yè)務(wù)要求:

如果end_at早于當前時間,則設(shè)置start_at為當前時間,end_at為當前時間加上續(xù)買的月數(shù)如果end_at等于或晚于當前時間,則設(shè)置end_at=end_at+續(xù)買的月數(shù)續(xù)買后active_status必須為1(即被激活)問題分析

對于上面這種情況,我們一般會先SELECT查出這條記錄,然后根據(jù)查出記錄的end_at再UPDATE start_at和end_at,偽代碼如下(為uid是1001的會員續(xù)1個月):

vipMember = SELECT * FROM vip_member WHERE uid=1001 LIMIT 1 # 查uid為1001的會員 if vipMember.end_at < NOW(): UPDATE vip_member SET start_at=NOW(), end_at=DATE_ADD(NOW(), INTERVAL 1 MONTH), active_status=1, updated_at=NOW() WHERE uid=1001 else: UPDATE vip_member SET end_at=DATE_ADD(end_at, INTERVAL 1 MONTH), active_status=1, updated_at=NOW() WHERE uid=1001

假如同時有兩個線程執(zhí)行上面的代碼,很顯然存在“數(shù)據(jù)覆蓋”問題(即一個是續(xù)1個月,一個續(xù)2個月,但最終可能只續(xù)了2個月,而不是加起來的3個月)。

解決方案

A、我想到的第一種方案是把SELECT和UPDATE合成一條SQL

如下:

UPDATE vip_member SET start_at = CASE WHEN end_at < NOW() THEN NOW()ELSE start_atEND, end_at = CASEWHEN end_at < NOW()THEN DATE_ADD(NOW(), INTERVAL #duration:INTEGER# MONTH)ELSE DATE_ADD(end_at, INTERVAL #duration:INTEGER# MONTH)END, active_status=1, updated_at=NOW()WHERE uid=#uid:BIGINT#LIMIT 1;

B、第二種方案:事務(wù),即用一個事務(wù)來包裹上面的SELECT+UPDATE操作

那么是否包上事務(wù)就萬事大吉了呢?

顯然不是。因為如果同時有兩個事務(wù)都分別SELECT到相同的vip_member記錄,那么一樣的會發(fā)生數(shù)據(jù)覆蓋問題。那有什么辦法可以解決呢?難道要設(shè)置事務(wù)隔離級別為SERIALIZABLE,考慮到性能不現(xiàn)實。

我們知道InnoDB支持行鎖。查看MySQL官方文檔(innodb locking reads)了解到InnoDB在讀取行數(shù)據(jù)時可以加兩種鎖:讀共享鎖和寫?yīng)氄兼i。

讀共享鎖是通過下面這樣的SQL獲得的:

SELECT * FROM parent WHERE NAME = ’Jones’ LOCK IN SHARE MODE;

如果事務(wù)A獲得了先獲得了讀共享鎖,那么事務(wù)B之后仍然可以讀取加了讀共享鎖的行數(shù)據(jù),但必須等事務(wù)A commit或者roll back之后才可以更新或者刪除加了讀共享鎖的行數(shù)據(jù)。

SELECT counter_field FROM child_codes FOR UPDATE;UPDATE child_codes SET counter_field = counter_field + 1;

如果事務(wù)A先獲得了某行的寫共享鎖,那么事務(wù)B就必須等待事務(wù)A commit或者roll back之后才可以訪問行數(shù)據(jù)。

顯然要解決會員狀態(tài)更新問題,不能加讀共享鎖,只能加寫共享鎖,即將前面的SQL改寫成如下:

vipMember = SELECT * FROM vip_member WHERE uid=1001 LIMIT 1 FOR UPDATE # 查uid為1001的會員if vipMember.end_at < NOW(): UPDATE vip_member SET start_at=NOW(), end_at=DATE_ADD(NOW(), INTERVAL 1 MONTH), active_status=1, updated_at=NOW() WHERE uid=1001else: UPDATE vip_member SET end_at=DATE_ADD(end_at, INTERVAL 1 MONTH), active_status=1, updated_at=NOW() WHERE uid=1001

另外這里特別提醒下:UPDATE/DELETE SQL盡量帶上WHERE條件并在WHERE條件中設(shè)定索引過濾條件,否則會鎖表,性能可想而知有多差了。

C、第三種方案:樂觀鎖,類CAS機制

第二種加鎖方案是一種悲觀鎖機制。而且SELECT...FOR UPDATE方式也不太常用,聯(lián)想到CAS實現(xiàn)的樂觀鎖機制,于是我想到了第三種解決方案:樂觀鎖。

具體來說也挺簡單,首先SELECT SQL不作任何修改,然后在UPDATE SQL的WHERE條件中加上SELECT出來的vip_memer的end_at條件。如下:

vipMember = SELECT * FROM vip_member WHERE uid=1001 LIMIT 1 # 查uid為1001的會員cur_end_at = vipMember.end_atif vipMember.end_at < NOW(): UPDATE vip_member SET start_at=NOW(), end_at=DATE_ADD(NOW(), INTERVAL 1 MONTH), active_status=1, updated_at=NOW() WHERE uid=1001 AND end_at=cur_end_atelse: UPDATE vip_member SET end_at=DATE_ADD(end_at, INTERVAL 1 MONTH), active_status=1, updated_at=NOW() WHERE uid=1001 AND end_at=cur_end_at

這樣可以根據(jù)UPDATE返回值來判斷是否更新成功,如果返回值是0則表明存在并發(fā)更新,那么只需要重試一下就好了。

方案比較

三種方案各自優(yōu)劣也許眾說紛紜,只說說我自己的看法:

第一種方案利用一條比較復雜的SQL解決問題,不利于維護,因為把具體業(yè)務(wù)糅在SQL里了,以后修改業(yè)務(wù)時不但需要讀懂這條SQL,還很有可能會修改成更復雜的SQL第二種方案寫?yīng)氄兼i,可以解決問題,但不常用第三種方案應(yīng)該是比較中庸的解決方案,并且甚至可以不加事務(wù),也是我個人推薦的方案

此外,樂觀鎖和悲觀鎖的選擇一般是這樣的(參考了文末第二篇資料):

如果對讀的響應(yīng)度要求非常高,比如證券交易系統(tǒng),那么適合用樂觀鎖,因為悲觀鎖會阻塞讀如果讀遠多于寫,那么也適合用樂觀鎖,因為用悲觀鎖會導致大量讀被少量的寫阻塞如果寫操作頻繁并且沖突比例很高,那么適合用悲觀寫?yīng)氄兼i
相關(guān)文章:
主站蜘蛛池模板: 欧美视频在线免费 | 91视频观看 | 九九精品在线 | 99re6在线视频精品免费 | 国产婷婷精品av在线 | 日韩精品日韩激情日韩综合 | 一区二区三区在线视频播放 | 二区在线观看 | 91午夜在线 | 日韩资源| 欧美日韩免费在线 | 欧美一区2区三区4区公司二百 | 国产欧美综合视频 | 国产中文一区二区三区 | 欧美高清视频在线观看 | 中文字幕在线第一页 | 日本黄色大片免费观看 | 久久伊| 伊人激情四射 | 国产情品| 毛片毛片毛片毛片毛片毛片 | 国产日韩一区二区三区 | 亚洲综合精品 | 蜜桃av一区二区三区 | 亚洲成人在线视频观看 | 国产精品178页 | 国产成人综合在线观看 | 黄色一级片免费 | 超碰在线一区二区三区 | 久久成人免费视频 | 精品久久久久久久久久久久 | 成人深夜福利视频 | 国产在视频一区二区三区吞精 | av一区二区在线播放 | 国产在线第一页 | 国产2区| 99亚洲精品| 美女久久 | 久久一区二区三区四区 | 激情欧美日韩一区二区 | 日本在线观看视频一区 |