日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql锁争用_关于MYSQL条件竞争与锁的问题

發(fā)布時間:2024/10/6 数据库 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql锁争用_关于MYSQL条件竞争与锁的问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

最近在整理關(guān)支付安全的內(nèi)容,其中就是涉及到了一個在支付過程中的條件競爭問題。以下都是基于mysql的與php的架構(gòu)來描述該問題,大佬勿噴。

0x01. 條件競爭

什么是條件競爭:

競爭條件?發(fā)生在多個線程同時訪問同一個共享代碼、變量、文件等沒有進行鎖操作或者同步操作的場景中。【W(wǎng)ikipedia-computer_science】

一個簡單的購買的業(yè)務(wù):

后臺代碼實現(xiàn)如下:

以上是一個購買商品的流程,看似并沒有什么問題。

如果每次請求都是一個單線程的請求是沒有什么問題的,但是如果采用多線程的并發(fā)請求就會出現(xiàn)問題。

因為每次的購買流程都是需要一定的時間去按照購買的流程執(zhí)行,如果我們在第一次購買的流程3還沒有結(jié)束時,就再去執(zhí)行這一遍流程時,那么在第流程2時查詢用戶的余額就還是初始的余額,這是因為第一次購買的流程3還沒有結(jié)束,沒有結(jié)束也就意味著余額沒有扣除,所以金額就是初始的值。

在上面的百年青花瓷購買的案例中,如果我們只有1000塊錢,但是我們在多線程的情況下去購買青花瓷的時候就可能購買到10件以上的數(shù)目。

0x02. 實際測試

在數(shù)據(jù)庫查看用戶數(shù)據(jù)

2.打開購買頁面

打開burp攔截購買商品的數(shù)據(jù)包,點擊購買。

設(shè)置intruder發(fā)送50個數(shù)據(jù)包,線程調(diào)到25后發(fā)包

并發(fā)請求后查看購買頁面,已擁有17件,余額成了-700。

我們調(diào)出mysql的查詢?nèi)罩尽?/p>

從日志中可以看到我們的請求是并發(fā)的執(zhí)行的,在一次查詢還沒有結(jié)束時就進行了下一次的查詢,所以這也很容易產(chǎn)生兩次查詢的余額是相同的。

所以當(dāng)我只剩100塊的只能購買一件商品的時候,但是有可能兩次查詢余額都100,是符合購買流程的操作的,后面也會對余額100進行兩次扣除操作,所以最后余額變成了負數(shù),購買的數(shù)量也大于10。

0x03. Solve the problem

mysql事務(wù)

在網(wǎng)上看到一篇關(guān)于mysql與php的條件競爭的分析中的解決方案是這樣的:

這種解決的方案的意思是給mysql查詢進行一個事務(wù)的處理,在mysql的查詢前添加一個BEGIN,開始一個事務(wù),在結(jié)束時添加一個COMMIT提交一個事務(wù),完成一個查詢操作。

本地測試一下

設(shè)置好線程再次并發(fā)購買一次,結(jié)果發(fā)現(xiàn)還是失敗了。并沒有解決條件競爭帶來的問題,所以解決方案是不行的。

什么是mysql的事務(wù)

事務(wù)是一組原子性sql查詢語句,被當(dāng)作一個工作單元。若mysql對改事務(wù)單元內(nèi)的所有sql語句都正常的執(zhí)行完,則事務(wù)操作視為成功,所有的sql語句才對數(shù)據(jù)生效,若sql中任意不能執(zhí)行或出錯則事務(wù)操作失敗,所有對數(shù)據(jù)的操作則無效(通過回滾恢復(fù)數(shù)據(jù))。

通過上面一句話差不多就知道了原因,只有在查詢語句不能執(zhí)行或出錯則事務(wù)操作失敗, 所以我們添加事務(wù)并不能解決mysql競爭的問題,因為我們的查詢是不會錯誤的,既然不會出錯也就會照樣執(zhí)行并發(fā)的請求。

0x04. mysql鎖

悲觀鎖

悲觀并發(fā)控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)是一種并發(fā)控制的方法。它可以阻止一個事務(wù)以影響其他用戶的方式來修改數(shù)據(jù)。如果一個事務(wù)執(zhí)行的操作對某行數(shù)據(jù)應(yīng)用了鎖,那只有當(dāng)這個事務(wù)把鎖釋放,其他事務(wù)才能夠執(zhí)行與該鎖沖突的操作。 悲觀并發(fā)控制主要用于數(shù)據(jù)爭用激烈的環(huán)境,以及發(fā)生并發(fā)沖突時使用鎖保護數(shù)據(jù)的成本要低于回滾事務(wù)的成本的環(huán)境中。

當(dāng)我們查詢的數(shù)據(jù)隨時可能會被其他操作修改時,我們對這個數(shù)據(jù)進添加一個悲觀鎖,如果想再次對這個數(shù)據(jù)進行操作時,只有這條查詢的操作結(jié)束后釋放這個悲觀鎖,其他查詢才可以對這條數(shù)據(jù)進行操作,如果鎖定沒有結(jié)束時,其他查詢會一直進行一個等待的狀態(tài)。

mysql 悲觀鎖的實現(xiàn)

select * from goods where id = 1 for update;

for update僅適用于InnoDB引擎,且必須在事務(wù)塊(BEGIN/COMMIT)中才能生效。在進行事務(wù)操作時,通過“for update”語句,MySQL會對查詢結(jié)果集中每行數(shù)據(jù)都添加排他鎖,其他線程對該記錄的更新與刪除操作都會阻塞。排他鎖包含行鎖、表鎖。

使用悲觀鎖解決上述并發(fā)問題:

并發(fā)測試:

經(jīng)過多次測試后發(fā)現(xiàn)商品購買正常。沒有出現(xiàn)條件競爭的問題

我們這邊來看下后端mysql查詢的日志

我們吧mysql的查詢分成了11組

前七組都沒條件競爭的問題,所有操作都是有序執(zhí)行的,但是在第八組的時候開始出現(xiàn)問題

在第八條數(shù)據(jù)查詢的事務(wù)還沒有結(jié)束時就開始查詢第九條的數(shù)據(jù)了

但是由于我們使用了for update(悲觀鎖),對select語句進行鎖定,所以在執(zhí)行到第九條的時候發(fā)現(xiàn)第八條的事務(wù)還沒有結(jié)束,所以他就只能等待第八條的更新完庫存之后執(zhí)行commit(提交事務(wù))操作,第八條查詢的鎖才會進行釋放,然后第九條查詢才能獲取到用戶的余額進行下一步操作。所以通過悲觀鎖解決了條件競爭帶來的問題。

但是悲觀鎖的弊端在每次查詢都會對數(shù)據(jù)進行鎖定,在高并發(fā)的請請求下會變得很慢。所以高并發(fā)的請求不建議使用悲觀鎖。

樂觀鎖

時間有限,下次再講

在這個寒冷的時節(jié)里

因為有你的關(guān)注

而變得溫暖

總結(jié)

以上是生活随笔為你收集整理的mysql锁争用_关于MYSQL条件竞争与锁的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。