本篇內(nèi)容介紹了“PHP并發(fā)如何保證數(shù)據(jù)的一致性”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)公司專(zhuān)業(yè)為企業(yè)提供周村網(wǎng)站建設(shè)、周村做網(wǎng)站、周村網(wǎng)站設(shè)計(jì)、周村網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、周村企業(yè)網(wǎng)站模板建站服務(wù),十多年周村做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
業(yè)務(wù)場(chǎng)景分析
用戶(hù)購(gòu)買(mǎi)商品的邏輯中,需要對(duì)用戶(hù)錢(qián)包的余額進(jìn)行查詢(xún)和扣款。如果同一用戶(hù)并發(fā)執(zhí)行多個(gè)業(yè)務(wù)進(jìn)行” 查詢(xún) + 扣款” 的業(yè)務(wù)中有一定概率出現(xiàn)數(shù)據(jù)不一致。
Tips:如果沒(méi)有做限制單一接口請(qǐng)求頻率,用戶(hù)使用并發(fā)請(qǐng)求的手段也有概率出現(xiàn)數(shù)據(jù)不一致。
1: 從數(shù)據(jù)庫(kù)查詢(xún)用戶(hù)錢(qián)包余額
SELECT balance FROM user_wallet WHERE uid = $uid; +---------+| balance | +---------+| 100 | +---------+1 row in set (0.02 sec)
2: 業(yè)務(wù)邏輯
Tips: 文章分享處理同一用戶(hù)并發(fā)扣款一致性,檢查庫(kù)存啥的邏輯略過(guò)
1. 查詢(xún)商品價(jià)格,比如 70 元
2. 商品價(jià)格對(duì)比余額是否足夠,足夠時(shí)進(jìn)行扣款提交訂單邏輯
if(goodsPrice <= userBalance) { $newUserBalance = userBalance - goodsPrice; }else { throw new UserWalletException(['msg' => '用戶(hù)余額不足']); }
3: 將數(shù)據(jù)庫(kù)的余額進(jìn)行修改
UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid
在沒(méi)有并發(fā)的情況下,這個(gè)流程沒(méi)有任何問(wèn)題,原有余額 100,購(gòu)買(mǎi) 70 元的商品,剩余 30 元
1: 用戶(hù)并發(fā)購(gòu)買(mǎi)業(yè)務(wù) A 和業(yè)務(wù) B(不同實(shí)例 / 服務(wù)),一定概率并行查詢(xún)余額是 100
3:
1 業(yè)務(wù) A 先進(jìn)行修改,修改余額為 30
此時(shí)異常出現(xiàn)了,原余額 100 元,業(yè)務(wù) A 和業(yè)務(wù) B 的商品價(jià)格總和 150 元(70+80)都購(gòu)買(mǎi)成功且余額還剩 20 元。
異常點(diǎn):業(yè)務(wù) A 和業(yè)務(wù) B 并行查詢(xún)余額為 100
悲觀鎖
使用 redis 悲觀鎖,例如搶到一個(gè) KEY 才能繼續(xù)操作,否則禁止操作
封裝了一個(gè)開(kāi)箱即用的 RedisLock
connect('127.0.0.1','6379'); $lockTimeOut = 5; $redisLock = new RedisLock($redis,$lockTimeOut); $lockKey = 'lock:user:wallet:uid:1001'; $lockExpire = $redisLock->getLock($lockKey);if($lockExpire) { try { //select user wallet balance for uid $userBalance = 100; //select goods price for goods_id $goodsPrice = 80; if($userBalance >= $goodsPrice) { $newUserBalance = $userBalance - $goodsPrice; //TODO set user balance in db }else { throw new Exception('user balance insufficient'); } $redisLock->releaseLock($lockKey,$lockExpire); } catch (\Throwable $throwable) { $redisLock->releaseLock($lockKey,$lockExpire); throw new Exception('Busy network'); } }
樂(lè)觀鎖
使用 CAS(Compare And Set)
在 set 寫(xiě)回的時(shí)候,加上初始狀態(tài)的條件 compare, 只有初始狀態(tài)不變的時(shí)候才允許 set 寫(xiě)回成功,保證數(shù)據(jù)一致性的方法
UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid
改為:
UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid AND balance = $oldUserBalance
這樣的話并發(fā)操作時(shí)只有一個(gè)是執(zhí)行成功的,根據(jù) affect rows 是否為 1 判斷是否成功
“PHP并發(fā)如何保證數(shù)據(jù)的一致性”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!