成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

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

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

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

問題背景

假設MySQL數據庫有一張會員表vip_member(InnoDB表),結構如下:

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

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

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

對于上面這種情況,我們一般會先SELECT查出這條記錄,然后根據查出記錄的end_at再UPDATE start_at和end_at,偽代碼如下(為uid是1001的會員續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

假如同時有兩個線程執行上面的代碼,很顯然存在“數據覆蓋”問題(即一個是續1個月,一個續2個月,但最終可能只續了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、第二種方案:事務,即用一個事務來包裹上面的SELECT+UPDATE操作

那么是否包上事務就萬事大吉了呢?

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

我們知道InnoDB支持行鎖。查看MySQL官方文檔(innodb locking reads)了解到InnoDB在讀取行數據時可以加兩種鎖:讀共享鎖和寫獨占鎖。

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

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

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

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

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

顯然要解決會員狀態更新問題,不能加讀共享鎖,只能加寫共享鎖,即將前面的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條件中設定索引過濾條件,否則會鎖表,性能可想而知有多差了。

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

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

具體來說也挺簡單,首先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

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

方案比較

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

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

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

如果對讀的響應度要求非常高,比如證券交易系統,那么適合用樂觀鎖,因為悲觀鎖會阻塞讀如果讀遠多于寫,那么也適合用樂觀鎖,因為用悲觀鎖會導致大量讀被少量的寫阻塞如果寫操作頻繁并且沖突比例很高,那么適合用悲觀寫獨占鎖
標簽: MySQL 數據庫
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
日韩欧美一卡二卡| 午夜欧美理论片| 亚洲成a人在线观看| a亚洲天堂av| 欧美亚州韩日在线看免费版国语版 | 精品一区二区在线免费观看| 欧美精品v日韩精品v国产精品| 欧美日韩国产精选| 亚洲午夜一区二区三区| 成人黄色一级视频| 欧美日韩在线综合| 三级影片在线观看欧美日韩一区二区 | 日韩在线观看一区二区| 91免费精品国自产拍在线不卡| 免费xxxx性欧美18vr| 久久夜色精品一区| **性色生活片久久毛片| 国产盗摄一区二区| 欧美激情在线看| 综合激情网...| 女同一区二区| 午夜精品久久久久久不卡8050 | 女女同性精品视频| 黄一区二区三区| 久久久精品蜜桃| 欧美专区日韩专区| 亚洲精品在线二区| 久久97超碰国产精品超碰| 91久久夜色精品国产九色| 中文字幕乱码亚洲精品一区| 欧美理论在线| 中文字幕一区二区三区不卡在线| 精品不卡一区| 亚洲国产一区二区三区青草影视| 一区二区久久| 亚洲成人在线免费| 久久精品日产第一区二区| 日韩一区精品视频| 欧美日韩高清在线| 成人综合婷婷国产精品久久| 8x福利精品第一导航| 国产麻豆精品theporn| 日韩欧美国产一区在线观看| 91麻豆产精品久久久久久| 国产精品电影一区二区三区| 国产伦精品一区二区三区四区免费| 午夜精品久久久久久久99水蜜桃| 欧美午夜精品久久久久久孕妇| 国产成人综合亚洲网站| 国产欧美一区二区精品忘忧草| 国产精品xvideos88| 亚洲激情中文1区| 欧美综合国产| 免费在线观看不卡| 91麻豆精品国产91久久久使用方法| 国产乱对白刺激视频不卡| www国产精品av| 欧美色欧美亚洲另类七区| 亚洲图片激情小说| 久久久久久久久久久久久久一区| 久久av资源网| 久久免费美女视频| 亚洲激情另类| 日本欧美肥老太交大片| 欧美精品乱码久久久久久| 成人丝袜视频网| 国产精品国产精品国产专区不蜜| 午夜在线精品| 国产在线精品一区二区三区不卡| 久久尤物电影视频在线观看| 欧美色图首页| 亚洲 欧美综合在线网络| 欧美日本国产一区| 午夜精品电影| 五月综合激情婷婷六月色窝| 在线播放中文一区| 欧美午夜精品| 日日噜噜夜夜狠狠视频欧美人 | 成人av电影观看| 亚洲黄色小视频| 欧美日韩国产综合一区二区三区| 91网址在线看| 亚洲二区在线视频| 欧美男生操女生| 欧美精品三级| 丝袜亚洲另类欧美| 日韩欧美国产三级电影视频| 伊伊综合在线| 免费观看久久久4p| 国产亚洲精品资源在线26u| 在线视频一区观看| 国产一区二区三区电影在线观看| 国产精品久久综合| 在线观看不卡一区| 女同性一区二区三区人了人一| 婷婷综合在线观看| www国产精品av| 久久成人国产| 成人黄色片在线观看| 有码一区二区三区| 日韩欧美不卡在线观看视频| 香蕉免费一区二区三区在线观看| 成人网男人的天堂| 亚洲成a人v欧美综合天堂下载| 日韩欧美一区二区视频| 国产九九精品| 成人av资源在线| 天天影视色香欲综合网老头| 久久日韩精品一区二区五区| 久久午夜精品| 欧美日韩精品伦理作品在线免费观看| 日本人妖一区二区| 国产精品日日摸夜夜摸av| 欧美艳星brazzers| 亚洲国产二区| 成人在线视频一区二区| 五月天欧美精品| 国产精品剧情在线亚洲| 91精品免费在线观看| 亚洲一区国产| 欧美日韩免费观看一区| 国产精品一二三四五| 亚洲午夜久久久久久久久电影网| 欧美成人vr18sexvr| 在线看一区二区| 在线日韩视频| 成人av电影在线播放| 蜜臀久久99精品久久久久宅男| 中文字幕日本乱码精品影院| 欧美xingq一区二区| 久久久久一区二区三区| 欧美三级网页| 成人午夜在线免费| 麻豆成人免费电影| 亚洲小说春色综合另类电影| 欧美激情综合五月色丁香| 4438x成人网最大色成网站| 亚洲欧美日本国产专区一区| 国产精品久久7| 99精品黄色片免费大全| 国内成+人亚洲+欧美+综合在线| 亚洲午夜影视影院在线观看| 国产精品久久久久久久久快鸭| 欧美xxxxx裸体时装秀| 欧美日韩三级一区| 色婷婷综合中文久久一本| 极品av少妇一区二区| 成人精品一区二区三区四区| 韩国欧美一区二区| 亚洲大尺度视频在线观看| 亚洲色图欧洲色图| 国产农村妇女精品| 精品乱码亚洲一区二区不卡| 欧美日产国产精品| 色婷婷综合久久久久中文一区二区| 在线欧美视频| 欧美日韩一区二区三区四区在线观看| 国产精品一区二区免费不卡| 亚洲国产成人高清精品| 久久免费午夜影院| 91麻豆精品国产91久久久使用方法 | 午夜精品一区在线观看| 亚洲日本一区二区三区| 国产欧美一区二区精品性色| 26uuu亚洲婷婷狠狠天堂| 69堂精品视频| 在线综合+亚洲+欧美中文字幕| 欧美日韩一区二区三区高清| 色乱码一区二区三区88| 久久国产精品一区二区三区| 亚洲理论在线| 悠悠资源网久久精品| 欧美日韩高清免费| 91视频一区二区三区| 91在线观看高清| 成人动漫在线一区| 国产91在线|亚洲| 国产精品白丝av| 久久se这里有精品| 人人精品人人爱| 日韩精品福利网| 欧美日本一道本| 欧美日韩综合在线| 精品视频在线免费观看| 91黄色在线观看| 久久综合狠狠| 在线免费观看一区| 欧美丝袜丝nylons| 欧美日韩国产成人在线91| 91麻豆精品国产91久久久久久久久 | 欧美日韩大陆在线| 欧美亚洲综合网| 欧美日韩mp4| 日韩免费一区二区三区在线播放| 日韩免费在线观看| 国产婷婷一区二区| ㊣最新国产の精品bt伙计久久| 亚洲九九爱视频| 日本美女一区二区三区视频| 国产一区二区在线看|