表结构
1 | CREATE TABLE `user_balance` ( |
操作用户余额时注意
- 可重复读(记录扣费后余额快照)(select
coin
后记录到user_balance_log表的coin_after
) - 乐观锁(扣费冲突)(set
coin
- 1000 wherecoin
>= 1000) - 业务幂等(不同业务使用相应的订单表)
- 事务(用户余额表
user_balance
、日志流水表user_balance_log
、业务订单表绑定) - canal 监听 binlog 识别业务异常 (对比 binlog监听的
user_balance
表coin
变化量 和user_balance_log
的coin
记录总量 是否一致)
流水表只需要记录coin_after
事务过程
事务1 | 事务2 |
---|---|
BEGIN; | |
BEGIN; | |
SELECT * FROM user_balance WHERE user_id = ‘kxw’; (coin=20000000) |
|
UPDATE user_balance SET coin = coin - 1000 WHERE user_id = ‘kxw’ AND coin >= 1000; |
|
SELECT * FROM user_balance WHERE user_id = ‘kxw’; (coin=20000000) |
|
UPDATE user_balance SET coin = coin - 1000 WHERE user_id = ‘kxw’ AND coin >= 1000; |
|
SELECT * FROM user_balance WHERE user_id = ‘kxw’; (coin=19999000) |
|
COMMIT; | |
SELECT * FROM user_balance WHERE user_id = ‘kxw’; (coin=19998000) |
|
COMMIT; |
- 流水表只需要记录
coin_after
(变更后的余额)即可,因为变更前的余额,可能因为并发导致不准确,除非开启事务后,使用select for update
来查询,而不是用普通的快照读