中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP并發如何保證數據的一致性

發布時間:2021-07-02 15:41:23 來源:億速云 閱讀:359 作者:chen 欄目:編程語言

本篇內容介紹了“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

PHP并發如何保證數據的一致性

3:

1 業務 A 先進行修改,修改余額為 30

PHP并發如何保證數據的一致性

此時異常出現了,原余額 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并發如何保證數據的一致性”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

措勤县| 射阳县| 定日县| 天镇县| 凉山| 辛集市| 荥经县| 贵州省| 陆河县| 鄂尔多斯市| 襄樊市| 尼玛县| 安徽省| 马龙县| 镶黄旗| 永嘉县| 上思县| 昆明市| 邢台县| 芷江| 昌江| 阳原县| 鸡东县| 龙州县| 思茅市| 中牟县| 桐城市| 安溪县| 普兰店市| 鄂尔多斯市| 泽州县| 定边县| 梧州市| 德阳市| 辽阳县| 河间市| 黄梅县| 宁化县| 聂荣县| 手游| 九台市|