您好,登录后才能下订单哦!
本篇内容介绍了“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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。