1,问题:
在高并发系统中,存在热点账户现象,即一个账户有大量的入账和扣账请求,在这样的背景下,频繁的更新账户的余额会对数据库造成较大的压力。
2,解决思路:
update改为insert。创建待入账流水表和待扣账流水表。批量更新账户余额。
4,引出的新问题:
入账好说,扣账需要注意一点,就是在余额系统中,余额的值不能为负。
5,解决思路:
在插入待扣账流水之前要进行余额检查。即余额-代扣流水总额>0。
6,引出的新问题:
待扣账流水终究要更新到余额的,这时会有并发问题,描述如下:
定时执行批量更新的线程 | 插入待扣流水线程 | ||
T1 | 按照时间段获取一批待扣流水 | ||
T2 | 更新余额完成(开启事务A) | ||
T3 | 查询余额(会获得已经更新的旧值) | ||
T4 | 查询待扣流水总额 | ||
T5 | 删除待扣流水(事务A提交) | ||
T6 | 余额检查 |
这会产生实际余额可扣账,但是检查失败的情况。但是,从业务安全的角度来说,余额没有变负,牺牲了用户体验。还会有一种问题:
定时执行批量更新的线程 | 待扣账流水线程 | |
T1 | 按照时间段获取一批待扣流水(100元) | |
T2 | 查询余额(110元) | |
T3 | 更新余额(开启事务A)(110元-100元=10元) | |
T4 | 删除待扣流水(事务A提交) | |
T5 | 查询待扣流水总额(0元) | |
T6 | 余额检查(110元-0元-本次扣账100元>0,检查通过) |
T4,T5还可能发生一部分删除,一部分未删除时,T5开始查询。