支付系统容易遇到的一个问题就是,账户的余额更新问题,账户的入款和出款会更新账户的余额,在并发情况下,如果通过普通的更新操作,容易造成账户余额变更负数。因此更新账户余额时需要事务控制,保证共享和的一致性。下面个人整理了一个解决方案,供大家参考,大家若有更好的方案,欢迎留言。
方案一:一般更新语句
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、并发情况下,成功率很高,会存在阻塞问题,造成数据库压力大。