支付系统 遇到了一个读取账户余额加锁的问题 该如何解决

发布于 2022-09-11 14:56:13 字数 634 浏览 40 评论 0

第一次做支付系统,我们平台有很多商户,每个商户每分钟订单很多,量很大,我用异步方式给商户账户更新余额,用的mysql队列,每笔订单成功都会往队列里加如一条,crontab来读取更新增加账户余额,但是碰到了一个提现的问题

提现我是这么做的,账户余额减去提现金额,然后再把剩余的钱更新到账户余额字段,问题就有了!

1.提现的时候拿到账户余额为10块,要提现5块,提现操作正在进行,但是这个时候进来一笔5块的订单,异步要更新账户,拿到的还是10块,加上5块,然后把15元更新到余额字段中,这时候提现操作也在进行,提现了5块,然后在把剩余的5块更新到余额字段, 覆盖了之前的15,

2.我没有在提现查询余额的时候加锁,加锁能否解决问题呢,除了加锁,是否还有其他更好的方法解决呢。这个异步更新账户余额的逻辑和提现的逻辑是否需要改进呢。希望大家能能大家给点意见谢谢

第一条是入账的,第一个字段是ID 第二个余额,第三个订单金额,第四个更新完后的余额,
第二条是提现的,第二个余额,第三个是提现的金额,第四个同上

clipboard.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

舟遥客 2022-09-18 14:56:13

乐观锁了解下。
余额表加个版本号字段,每次操作余额版本号+1,在更新余额之前,先取得版本号,更新的过程:

select version from table order by version desc limit 1;

update table set balace = xx,version = version + 1 where version = xx;

如果更新失败(返回0)则继续以上操作,这叫自旋锁。

酒中人 2022-09-18 14:56:13

首先,用户账户的操作是需要加锁的,不管是消费还是充值,都需要加锁操作。比如,充值时要先获取一个账户锁,获取成功后,其他操作比如消费,就无法获取账户锁了,只能等待锁释放。
其次,可以在SQL语句中加一个条件来达到账户变动的则失败效果,例如:

update user set balance = balance+5 where user_id = xxx AND balance = 5;

加入原先余额是5,现在要充值5,则条件中要加上balance=5,这样,如果余额被修改过,则更新失败。不至于覆盖数据。

再次,用户余额的变动需要有流水的,当金额不匹配的时候,可以通过流水回溯。

﹂绝世的画 2022-09-18 14:56:13

绝对是开启事务,用for update加锁的..因为还要记流水,流水需要用到用户的当前余额
如果是不需要用到用户的当前余额,你可以试试sql的原子操作:

update user set balance = balance-10 where user_id = xxx;
紫南 2022-09-18 14:56:13

增加余额

set autocommit=0;
update <table> set balance=balance+<xxx> where id=<id>;
select * from <table> where id=<id>
commit;

保证上面2条语句在同一个事务中执行。最终在程序中做运算。

  • balance - <xxx> 就是增加前的余额
  • balance 就是增加后的余额

提现

set autocommit=0;
update <table> set balance=balance-<xxx> where id=<id> and balance>=<xxx>;
select * from <table> where id=<id>;
commit;

保证上面2条语句在同一个事务中执行。最终在程序中做运算。

  • balance + <xxx> 就是提现前的余额
  • balance 就是提现后的余额
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文