线上账务系统余额并发更新问题记录

某电商平台,某天线上用户报bug说账户余额信息与交易流水对不上。可以认为是数据库并发更新问题,由此定位出具体原因,并给出解决方案。

问题现象

场景描述

线上账务系统,在定时结算给卖家钱时,且高并发量的情况下,出现提现x元(假设当前用户余额为x元)余额为0后,再转入该账户一笔钱(假设为y元),结果账户余额变为了x+y 元,导致用户余额错误。 ps:账户余额的变更都是在事务中update的

环境说明

mysql5.7 + innodb,事务隔离级别是REPEATABLE-READ

场景模拟

我们简化下线上的数据结构,进行场景模拟。 数据表如下: ‘账户主表’

 

‘账户余额明细表’

 

账户类型配置

 

具体数据为:

 

模拟提现(即余额减)和入账(即余额加)并发操作的事务如下:

session1-提现10元 session2-入账20元
begin;
select description from user_conf where type_id = 100;
select * from user where uid = 10001 for update; /user表用来做互斥
select amount from user_account where uid = 10001; /10c0b700
begin;
select description from user_conf where type_id = 100;
select * from user where uid = 10001 for update; /wating
/wating
update user_account set amount = 0.00 where uid = 10001;
commit;
拿到锁
select amount from user_account where uid = 10001; /10.00
入账20元,代码中计算后应该为30元
update user_account set amount = 30.00 where uid = 10001;
commit;

问题出现了,后面再查询该用户余额为30元,即用户提现的10元未反映在余额中

原因定位

熟悉mysql的同学或许已经知道问题是由REPEATABLE-READ隔离级别下快照读导致

具体解释:

RR级别下,第一次读操作会生成快照,对于可见性来说,只有当第一次读之前其他事务提交的修改和自己的修改可见,其他的均不可见。

官网文档:ag娱乐平台/devc0b7mysqlc0b7com/doc/refman/5.7/en/glossary.html snapshot A representation of data at a particular time, which remains the same even as changes are committed by other transactions.

With REPEATABLE READ isolation level, the snapshot is based on the time when the first read operation is performed.

可见性原理

可参考文章:ag娱乐平台/hedengchengc0b7com/?p=148

回到上述模拟场景中,session2在sql语句select description from user_conf where type_id = 100; 时已生成快照,虽然session1提交了,但仍然不可见,导致并发更新问题。

另外,开启事务后,SELECT … FOR UPDATE 是不会生成快照的,大家可自行实验

解决方案

方案一

将REPEATABLE-READ隔离级别改为READ-COMMITTED,这样即能看到最新提交的数据。

方案二

在读’账户余额明细表’user_account 的时候加 for update,这样会 1.强制读该行记录的最新版本数据,2.且若其他事务未commit,本事务将阻塞,保证串行更新

方案三

延时生成快照。开启事务后,首先就通过user表做互斥,直接for update加锁,针对多个事务并发更新即变为串行。

附:定位过程

  1. 针对上报bug用户,查询其交易流水明细与余额变更明细,确认账务存在问题
  2. 查询账务系统近几天是否有上线变更,检查无
  3. 拉取账务数据库mysql general log,找到并发更新的两个事务session
  4. 查询数据库设置的隔离级别为RR,查询应用数据库连接池配置即session的隔离级别未配置,采用数据库配置
  5. 确认由RR级别导致(当然也可以认为是代码问题导致)
  6. 确认是一个月前账务系统分库分表上线,改用其他连接池且未设置session隔离级别。而之前是有配置session的隔离级别为READ-COMMITTED。

延伸思考

mysql RR级别适用的业务场景是什么,应该怎么选择? 有兴趣或有见解的同学可以留言回复或私信~~

参考

ag娱乐平台/blogc0b7csdnc0b7net/chen77716/article/details/6742128#comments

ag娱乐平台/hedengchengc0b7com/?p=148

/liuzhengyangc0b7githubc0b7io/2017/04/18/innodb-mvcc/

1 2 收藏 1 评论
大蒜滞销县长录视频代言 媒体:做法有违市场规律 孟加拉国外交部:尼起火飞机上有22人获救 商汤拿下AI领域单笔最大融资 估值超过45亿美元 美元升势似乎势不可挡 或拖累美股阻碍公司盈利增长 一图看懂:美国顶级CEO去年究竟拿了多少薪水 新浪彩票名家双色球第18086期推荐汇总 蔡英文如何才能走出四处被围的窘境?台媒支招 市民买到6瓶假茅台 超市被判付10倍赔偿金共9万元 太稳!前方记者一边倒看好塞尔比 27人竞猜21压他 高手在民间!赤脚小伙满分射九宫格 这脚法没得挑 美国智能制造项目东莞对接制造企业 中国2艘军舰在南海演习 发射数十枚炮弹击中靶船(图)
印度驻阿富汗大使馆遭袭击 3名嫌疑人遭逮捕 英超-奥巴梅扬进球 阿森纳1-2遭3连败距前四13分 欧洲和俄航空公司接通知:未来72小时叙利亚或遭打击 华为3GPP参会代表发文:也说联想NR FEC投票事件 小德赛季首进大师赛八强 再战锦织圭做好苦战准备 患者换肾后因病死亡 家属诉返还肾源费被法院驳回 女子春节被老鼠整得团团转 借了只宠物猫仍无效果 小作坊制假冒海淘爆款:国内造假运出国外“镀金” 胡耀宇:读秒中的李昌镐一招不慎 酿成生死劫争 蚂蚁金服将融资超100亿美元 估值约1500亿美元 苏格兰首席部长:英退欧形势明朗后将考虑再独立公投 东吴证券深度报告闹乌龙折射风控缺陷 净利暴跌反衬经营堪…
疑因美航备降后安排不周 中国夫妇赴美探亲遇车祸 有毒物质成制作玩具原料 小学生误食致中毒(图) 小额支付市场硝烟再起 银联卡小额免密上限升至千元 直击|百度宣布陆奇将不再任总裁兼COO 留任副董事长 IBM本来要用Watson来抗癌 结果被却医生骂为Sh… 贝尔凉了!7成球迷要求卖掉他 皇马生涯路已尽 Grab宣布进军共享单车市场 率先在新加坡推出服务 民生银行溃退:存款净流失超1100亿 员工锐减903人 缅甸边境爆发武装冲突 一枚疑似火箭炮落入云南 马英九春联首波10万份被抢光 蔡英文所写买者较少 俄战机被击落飞行员被杀 普京为何只进行有限报复 人民日报访克隆猴研究团队:世界难题这样攻克 江西上栗县一家烟花爆竹厂爆炸 现巨大蘑菇云 ag娱乐平台