您好,登錄后才能下訂單哦!
本篇內容介紹了“PHP并發如何保證數據的一致性”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
業務場景分析
用戶購買商品的邏輯中,需要對用戶錢包的余額進行查詢和扣款。如果同一用戶并發執行多個業務進行” 查詢 + 扣款” 的業務中有一定概率出現數據不一致。
Tips:如果沒有做限制單一接口請求頻率,用戶使用并發請求的手段也有概率出現數據不一致。
1: 從數據庫查詢用戶錢包余額
SELECT balance FROM user_wallet WHERE uid = $uid; +---------+| balance | +---------+| 100 | +---------+1 row in set (0.02 sec)
2: 業務邏輯
Tips: 文章分享處理同一用戶并發扣款一致性,檢查庫存啥的邏輯略過
1. 查詢商品價格,比如 70 元
2. 商品價格對比余額是否足夠,足夠時進行扣款提交訂單邏輯
if(goodsPrice <= userBalance) { $newUserBalance = userBalance - goodsPrice; }else { throw new UserWalletException(['msg' => '用戶余額不足']); }
3: 將數據庫的余額進行修改
UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid
在沒有并發的情況下,這個流程沒有任何問題,原有余額 100,購買 70 元的商品,剩余 30 元
1: 用戶并發購買業務 A 和業務 B(不同實例 / 服務),一定概率并行查詢余額是 100
3:
1 業務 A 先進行修改,修改余額為 30
此時異常出現了,原余額 100 元,業務 A 和業務 B 的商品價格總和 150 元(70+80)都購買成功且余額還剩 20 元。
異常點:業務 A 和業務 B 并行查詢余額為 100
悲觀鎖
使用 Redis 悲觀鎖,例如搶到一個 KEY 才能繼續操作,否則禁止操作
封裝了一個開箱即用的 RedisLock
<?phpuse Ar414\RedisLock; $redis = new \Redis(); $redis->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'); } }
樂觀鎖
使用 CAS(Compare And Set)
在 set 寫回的時候,加上初始狀態的條件 compare, 只有初始狀態不變的時候才允許 set 寫回成功,保證數據一致性的方法
UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid
改為:
UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid AND balance = $oldUserBalance
這樣的話并發操作時只有一個是執行成功的,根據 affect rows 是否為 1 判斷是否成功
“PHP并發如何保證數據的一致性”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。