欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2014年05月14日 09:52:24   作者:  
這篇文章主要介紹了MySQL中SELECT+UPDATE處理并發(fā)更新問題解決方案分享,需要的朋友可以參考下

問題背景:

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

 

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

•如果end_at早于當(dāng)前時(shí)間,則設(shè)置start_at為當(dāng)前時(shí)間,end_at為當(dāng)前時(shí)間加上續(xù)買的月數(shù)

•如果end_at等于或晚于當(dāng)前時(shí)間,則設(shè)置end_at=end_at+續(xù)買的月數(shù)

•續(xù)買后active_status必須為1(即被激活)

問題分析:

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

復(fù)制代碼 代碼如下:

vipMember = SELECT * FROM vip_member WHERE uid=1001 LIMIT 1 # 查uid為1001的會(huì)員
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

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

解決方案:

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

復(fù)制代碼 代碼如下:

UPDATE vip_member
SET
   start_at = CASE
              WHEN end_at < NOW()
                 THEN NOW()
              ELSE start_at
              END,
   end_at = CASE
            WHEN 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;

    So easy!

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

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

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

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

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

復(fù)制代碼 代碼如下:

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

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

復(fù)制代碼 代碼如下:

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ù)。

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

復(fù)制代碼 代碼如下:

vipMember = SELECT * FROM vip_member WHERE uid=1001 LIMIT 1 FOR UPDATE # 查uid為1001的會(huì)員
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

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

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

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

    具體來(lái)說(shuō)也挺簡(jiǎn)單,首先SELECT SQL不作任何修改,然后在UPDATE SQL的WHERE條件中加上SELECT出來(lái)的vip_memer的end_at條件。如下:

復(fù)制代碼 代碼如下:

vipMember = SELECT * FROM vip_member WHERE uid=1001 LIMIT 1 # 查uid為1001的會(huì)員
cur_end_at = vipMember.end_at
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 AND end_at=cur_end_at
else:
   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返回值來(lái)判斷是否更新成功,如果返回值是0則表明存在并發(fā)更新,那么只需要重試一下就好了。

方案比較:

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

•第一種方案利用一條比較復(fù)雜的SQL解決問題,不利于維護(hù),因?yàn)榘丫唧w業(yè)務(wù)糅在SQL里了,以后修改業(yè)務(wù)時(shí)不但需要讀懂這條SQL,還很有可能會(huì)修改成更復(fù)雜的SQL

•第二種方案寫?yīng)氄兼i,可以解決問題,但不常用

•第三種方案應(yīng)該是比較中庸的解決方案,并且甚至可以不加事務(wù),也是我個(gè)人推薦的方案


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

•如果對(duì)讀的響應(yīng)度要求非常高,比如證券交易系統(tǒng),那么適合用樂觀鎖,因?yàn)楸^鎖會(huì)阻塞讀

•如果讀遠(yuǎn)多于寫,那么也適合用樂觀鎖,因?yàn)橛帽^鎖會(huì)導(dǎo)致大量讀被少量的寫阻塞

•如果寫操作頻繁并且沖突比例很高,那么適合用悲觀寫?yīng)氄兼i

相關(guān)文章

  • MAC下mysql安裝配置方法圖文教程

    MAC下mysql安裝配置方法圖文教程

    這篇文章主要為大家分享了MAC下mysql安裝配置方法圖文教程,感興趣的朋友可以參考一下
    2016-06-06
  • MySQL啟動(dòng)錯(cuò)誤解決方法

    MySQL啟動(dòng)錯(cuò)誤解決方法

    本文給大家分享的是mysql啟動(dòng)時(shí)報(bào)錯(cuò)的排查過程及方法,非常實(shí)用,有相同問題的小伙伴可以來(lái)參考下
    2016-12-12
  • 聊聊MySQL中的存儲(chǔ)引擎

    聊聊MySQL中的存儲(chǔ)引擎

    MySQL是當(dāng)前流行的數(shù)據(jù)庫(kù)引擎之一,具有成本低、速度快、體積小且開放源代碼的優(yōu)點(diǎn)。這篇文章主要介紹了MySQL中存儲(chǔ)引擎的相關(guān)知識(shí),幫助大家更好的理解和學(xué)習(xí)數(shù)據(jù)庫(kù)技術(shù),感興趣的朋友可以了解下
    2020-08-08
  • Mysql數(shù)據(jù)庫(kù)高級(jí)用法之視圖、事務(wù)、索引、自連接、用戶管理實(shí)例分析

    Mysql數(shù)據(jù)庫(kù)高級(jí)用法之視圖、事務(wù)、索引、自連接、用戶管理實(shí)例分析

    這篇文章主要介紹了Mysql數(shù)據(jù)庫(kù)高級(jí)用法之視圖、事務(wù)、索引、自連接、用戶管理,結(jié)合實(shí)例形式分析了MySQL數(shù)據(jù)庫(kù)視圖、事務(wù)、索引、自連接、用戶管理常見用法及操作注意事項(xiàng),需要的朋友可以參考下
    2019-11-11
  • 幾個(gè)比較重要的MySQL變量

    幾個(gè)比較重要的MySQL變量

    這篇文章主要介紹了幾個(gè)比較重要的MySQL變量,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • MySQL恢復(fù)中的幾個(gè)問題解決方法

    MySQL恢復(fù)中的幾個(gè)問題解決方法

    這篇文章主要介紹了MySQL恢復(fù)中的幾個(gè)問題,需要的朋友可以參考下
    2016-01-01
  • mysql 5.7.12 winx64手動(dòng)安裝教程

    mysql 5.7.12 winx64手動(dòng)安裝教程

    這篇文章主要為大家詳細(xì)介紹了mysql 5.7.12 winx64手動(dòng)安裝配置方法圖文教程,感興趣的朋友可以參考一下
    2016-12-12
  • mysql特殊語(yǔ)法insert?into?..?on?duplicate?key?update?..使用方法詳析

    mysql特殊語(yǔ)法insert?into?..?on?duplicate?key?update?..使用方

    在我們的日常開發(fā)中經(jīng)常會(huì)遇到過這樣的情景,查看某條記錄是否存在,不存在的話創(chuàng)建一條新記錄,存在的話更新某些字段,下面這篇文章主要給大家介紹了關(guān)于mysql特殊語(yǔ)法insert?into?..?on?duplicate?key?update?..使用方法的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • MySQL中slave_exec_mode參數(shù)詳解

    MySQL中slave_exec_mode參數(shù)詳解

    本篇文章主要給大家講述了MySQL中slave_exec_mode參數(shù)的用法以及示例分析了出現(xiàn)的錯(cuò)誤問題和解決辦法,需要的朋友參考學(xué)習(xí)下吧。
    2017-12-12
  • 關(guān)于MySQL查詢語(yǔ)句的優(yōu)化詳解

    關(guān)于MySQL查詢語(yǔ)句的優(yōu)化詳解

    這篇文章主要介紹了MySQL查詢語(yǔ)句的優(yōu)化方法,分別介紹了子查詢優(yōu)化,分頁(yè)查詢優(yōu)化以及排序查詢優(yōu)化,對(duì)學(xué)習(xí)有一定的幫助,需要的小伙伴可以參考一下
    2023-04-04

最新評(píng)論