首页 > 技术文章 > 账号余额更新的问题,以及解决方案

zhaiMaoDou 2020-08-10 21:06 原文

  支付系统容易遇到的一个问题就是,账户的余额更新问题,账户的入款和出款会更新账户的余额,在并发情况下,如果通过普通的更新操作,容易造成账户余额变更负数。因此更新账户余额时需要事务控制,保证共享和的一致性。下面个人整理了一个解决方案,供大家参考,大家若有更好的方案,欢迎留言。

  方案一:一般更新语句

    update 语句 增加 if 判断语句,

    update account_tbl set balance = if(balance - amount>=0, balance - amount, '') where id= ?

    跟新余额,余额-金额>=0,更新余额=余额-金额,否侧 余额=“” 空值,抛异常,回滚数据

    需要注意的是:

    1、余额字段值不能为空

    2、余额字段数据类型不能是字符串

    3、并发较大的情况下,不能保证并发时会出现问题

    

  方案二:乐观锁

    利用乐观锁的版本号(version)进行控制

    查询

    select balance, version,...... from account_tbl where id=?

    判断

    balance - amonut >=0

    new_balance = balance - amount

    更新余额

    update account_tbl set balance = new_balance, version = version+1 weher id=? version=?

    更新返回1,更新成功,返回0,更新失败,需抛出异常,回滚事务!

    需要注意的是:

    1、查询和更新需要在同一个事务中处理

    2、并发情况下,只有一个请求成功,其余请求都失败,成功率较低

  方案三:悲观锁

    使用悲观锁(select ..... for update)进行行级别加锁

    查询时加锁

    select balance,...... from account_tbl where id=? for update 

    判断

    balance - amonut >=0

    new_balance = balance - amount

    更新余额

    update account_tbl set balance = new_balance weher id=? 

    更新返回1,更新成功,返回0,更新失败,需抛出异常,回滚事务!

    需要注意的是:

    1、查询和更新在同一个事务中处理

    2、并发情况下,成功率很高,会存在阻塞问题,造成数据库压力大。

 

推荐阅读