并发扣款,如何保证数据的一致性?
继承解答星球水友提问。 扣款的营业场景是奈何的? 用户购置商品的进程中,要对余额举办查询与修改,大抵的营业流程如下:第一步,从数据库查询用户现有余额:
不妨设查询出来的$old_money=100元。 第二步,营业层实验营业逻辑计较,好比:
第三步,将数据库中的余额举办修改。
在并发量低的环境下,这个流程没有任何题目,原有金额100元,购置了80元的九折商品(72元),剩余28元。 统一个用户,并发扣款也许呈现什么题目? 在漫衍式情形中,假如并发量很大,这种“查询+修改”的营业有必然概率呈现数据纷歧致。 极限环境下,也许呈现这样的非常流程: 步调一,营业1和营业2并发查询余额,是100元。 画外音:这些并发查询,是在差异的站点实例/处究竟例上完成的,历程内互斥锁必定办理不了。 步调二,营业1和营业2并发举办逻辑计较,算出各自营业的余额,假设营业1算出的余额是28元,营业2算出的余额是38元。 步调三,营业1对数据库中的余额先举办修改,配置成28元。营业2对数据库中的余额后举办修改,配置成38元。 此时非常呈现了,原有金额100元,营业1扣除了72元,营业2扣除了62元,最后剩余38元。 画外音:假设营业1先写回余额,营业2再写回余额。 常见的办理方案? 对付此案例,统一个用户,并发扣款时,有小概率会呈现非常,可以对每一个用户举办漫衍式锁互斥,譬喻:在redis/zk里抢到一个key才气继承操纵,不然榨取操纵。 这种气馁锁方案确实可行,但要引入特另外组件(redis/zk),而且会低落吞吐量。 对付小概率的纷歧致,有没有乐观锁的方案呢? 对并发扣款举办进一步的说明发明: (1) 营业1写回时,旧余额100,这是一个初始状态;新余额28,这是一个竣事状态。理论上只有在旧余额为100时,新余额才应该写回乐成。 而营业1并发写回时,旧余额确实是100,理应写回乐成。 (2) 营业2写回时,旧余额100,这是一个初始状态;新余额28,这是一个竣事状态。理论上只有在旧余额为100时,新余额才应该写回乐成。 可现实上,这个时辰数据库中的金额已经变为28了,以是营业2的并发写回,不该该乐成。 怎样低本钱实验乐观锁? 在set写回的时辰,加上初始状态的前提compare,只有初始状态稳固时,才应承set写回乐成,Compare And Set(CAS),是一种常见的低落读写锁斗嘴,担保数据同等性的要领。 此时营业要怎么改? 行使CAS办理高并发时数据同等性题目,只必要在举办set操纵时,compare初始值,假如初始值调动,不应承set乐成。 详细到这个case,只必要将:
即可。 并发操纵产生时:营业1执行:
营业2执行:
这两个操纵同时举办时,只也许有一个执行乐成。 怎么判定哪个并发执行乐成,哪个并发执行失败呢? set操纵,着实无所谓乐成可能失败,营业能通过affect rows来判定:
总结 高并发“查询并修改”的场景,可以用CAS(Compare and Set)的方法办理数据同等性题目。对应到营业,即在set的时辰,加上初始前提的比对即可。 优化不难,只改了半行SQL,但确实能办理题目。 但但愿各人有收成,思绪比结论重要。 【本文为51CTO专栏作者“58沈剑”原创稿件,转载请接洽原作者】 戳这里,看该作者更多好文
(编辑:湖南网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |