【支付系统】加减余额/库存,防止负数和脏读

文章讨论了在处理余额扣减时可能遇到的并发问题,包括脏读和负数余额。为了解决这些问题,提出了使用分布式锁(如Redis或Zookeeper)和乐观锁策略。在扣减前获取分布式锁,确保同一时间仅有一个请求操作,或者利用MyBatis-Plus的乐观锁功能,通过版本号检查来防止数据冲突。此外,还提供了SQL示例和Java代码片段来展示如何实施这些解决方案。
摘要由CSDN通过智能技术生成

       

        在使用进行余额扣减时,可能会遇到并发请求同时扣减同一余额的情况,这可能会导致脏读和负数余额的问题。为了解决这些问题,可以使用分布式锁来保证同一时间只有一个请求能够进行余额扣减操作。

        分布式锁可以使用redis或zookeeper等工具实现。在进行余额扣减前,先获取分布式锁。如果获取锁成功,则进行余额扣减操作,扣减完成后释放锁。如果获取锁失败,则说明有其他请求正在进行余额扣减操作,此时需要等待一段时间后重新尝试获取锁。

        在进行余额扣减操作时,需要先查询当前余额数量。如果当前余额数量小于等于0,则不能进行余额扣减,否则会导致负数余额的问题。如果当前余额数量大于0,则进行余额扣减操作,并更新数据库中的余额数量。

        同样我们也可以使用乐观锁。使用乐观锁时,先查询当前余额数量,并记录版本号。扣减余额时,检查当前余额数量和版本号是否一致,如果一致则进行扣减操作并更新版本号,否则说明有其他请求已经进行了余额扣减操作,此时需要重新查询当前余额数量和版本号,然后重新尝试扣减余额。

        总之,使用分布式锁和乐观锁等机制可以保证余额扣减操作的正确性和并发性,避免出现脏读和负数余额等问题

 首先通过sql对加减余额做个限制, 通过 balance + #{amount} >= 0; 限制修改余额的操作必须大于0

<update id="updateBalance">
        update `user`
        set balance = balance - #{amount}
        where id = #{userId}
          and balance - #{amount} >= 0;
</update>
  •  乐观锁

mybatis-plus 自带乐观锁功能 , 具体可以查看官方文档

  • 分布式锁
@Override
	public Boolean transfer(PlatformTransferReq req) throws InterruptedException {
        //定义锁 最好是根据人进行加锁
		RLock lock = redissonClient.getLock(RedisKey.BALANCE + req.getUserId());
		try {
			if (lock.tryLock(3, 30, TimeUnit.SECONDS)) {
				// 校验余额
				MerUser merUser = getById(req.getId());
				BigDecimal balance = merUser.getBalance();
				Assert.isTrue(NumberUtil.isGreaterOrEqual(balance, req.getAmount()), "账户余额不足");
				//  减掉余额
				return  SqlHelper.retBool(baseMapper.updateBalance(req.getId(), req.getAmount()));

			}
		} catch (InterruptedException e) {
			throw new ServiceException("转账失败 :" + e.getMessage());
		} finally {
			if (lock.isLocked()) {
				lock.unlock();
			}
		}
		return false;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲸渔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值