由并发扣款如何保证数据一致性引起的ABA问题的思考

账户余额并发扣款如何保证数据一致性 简介 很多业务系统中都离不开到余额系统,余额系统可以为客户提供一个虚拟账户,用户可以充值,然后使用账户中的余额购买平台内的商品,如果平台做的比较大后,也可以支持用户账户间的交易,如转账、收款等业务等等。 本文将系统性的梳理一下余额系统的整体设计,内容有 常见账户并发扣款设计对比 余额系统核心业务梳理 余额系统数据表结构设计 账户并发扣款业务流程梳理 原文:地址 1、常见账户并发扣... 阅读详情

起因是看了公众号架构师之路 推送的一篇文章:并发扣款,如何保证数据的一致性?

1. 场景:

用户购买商品,对余额进行查询和修改,如果余额大于商品价格,购买商品并修改余额,单机或者无并发情况下,这个步骤没有任何问题;但分布式环境下,不同站点实例的多个业务操作同一个用户进行并发扣款(虽然我也不知道怎么会有这种场景,用户怎么可能在同一时间买多个商品),这样进程内互斥锁肯定无法起作用,最终导致数据不一致。以下是异常流程:

  1. 业务1和业务2并发查询余额,都是100元;
  2. 然后并发进行业务计算,业务1算出余额是28元,业务2算出余额是38元,
  3. 那么无论谁写回余额,都会覆盖另一个业务的操作结果。

这不就是第二类丢失更新吗?网上有一个关系表格图:
在这里插入图片描述
如图,mysql默认隔离级别为可重复读,能解决第二类丢失更新,那上面怎么这个是怎么回事?
这里有一个误区,所说能解决是基于update语句的加减不会丢失,比如 update t_account set money=money-1 where id=1, 如下:事务1在T3时刻查询余额为100,事务2在T5时刻执行update减1操作修改为99,T6时刻提交,由于可重复读,事务1在T7时刻再查询一次仍然为100,T8时刻执行update减1,执行完会发现变成98,即更新未丢失;

时刻事务1事务2
T1开始事务
T2开始事务
T3查询余额为100
T4查询余额为100
T5执行update减1,余额修改为99
T6提交事务
T7查询余额为100
T8执行update减1
T9查询余额为98
T10提交事务

而上面描述的业务操作是在代码层级实现,即先查询后修改,加减是在代码里操作的,所以产生丢失更新;

那么问题来了,为什么不直接执行update加减操作呢?因为并发情况下,缺少了查询判断,很有可能会把余额减成负数。

2. 解决方案

2.1 分布式锁

由于是分布式环境,采用分布式锁可以保证数据一致性,但是这是小概率事件,并且引入新组件(redis/zk),还会降低吞吐量。
分布式锁参考:https://blog.youkuaiyun.com/unclecoco/article/details/99442998

2.2 悲观锁

在查询语句加 for update,行记录加上排它锁,这样后来的事务会阻塞查询,这样就避免了数据不一致。

2.3 乐观锁

CAS(Compare And Swap):内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

通过CAS操作,即旧值和预期值相同时执行修改,例如:
update t_account set money=#{new_money} where id=#{id};
修改为:
update t_account set money=#{new_money} where id=#{id} and money=#{old_money};

这样在并发情况下,只能有一个修改成功,affect row为1;其他事务由于money不等于旧值,修改失败,affect row为0。

3. 思考

3.1 ABA问题

线程1准备用CAS修改变量值A为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A,然后线程1执行CAS时发现变量的值仍然为A,所以线程1的CAS操作成功。但实际上这时已经和最初不同了。有点场景可能没影响,但在下例堆栈操作,就会产生严重问题:

线程1:读取到栈顶为A,准备替换为B,结果为B.next=Y;
在这里插入图片描述
线程2:取出A,push X、A入栈;
在这里插入图片描述
线程1:栈顶仍然为A,执行CAS操作,实际结果B.next=X,并且此时堆栈结构已经发生变化;
在这里插入图片描述

Java中以AtomicInteger为例可能产生ABA问题,可采用版本戳version来对记录或对象标记解决这个问题,AtomicStampedReference<E>就是实现了这个作用。

那么在题中的场景,事务2将余额修改后,如果又进行了一系列其他操作,最后余额等于旧值,事务1进行CAS操作成功,这就是ABA问题。

3.2 解决方案

基于值的CAS乐观锁,可能产生ABA问题。
这个问题可以通过加版本号的方案解决,本质还是CAS乐观锁,数据库增加一个版本号字段version,引入版本号,每次查询把版本号也查询出来,修改后比对版本号,如果期间其他事务修改过这条行记录,那么由于版本号不匹配,一定会修改失败。如下:
update t_account set money=#{new_money} where id=#{id} and money=#{old_money};
修改为:
update t_account set money=#{new_money} , version=#{new_version} where id=#{id} and version=#{old_version} ;

DCDC BUCK开关电源PCB设计 在开关电源中,BUCK(降压)电路、BOOST(升压)电路以及BUCK - BOOST(升降压)三种电路是最基本的拓扑结构。转换器又分DCDC(直流转直流)和ACDC(交流转直流),DCDC装换器结构无疑是比ACDC转换器结构简单,所以从DCDC转换器结构入手学习开关电源是一种很好的选择。本文主要从应用角度,进行相关器件的选型计算以及PCB绘制讲解DCDC 12V转5Vbuck电路。 阅读详情

相关推荐

Duplicate Cleaner Pro 5.16 保姆级教程:如何用哈希值精准清理重复文件(附音频/视频模式详解)

本文详细介绍了Duplicate Cleaner Pro 5.16如何利用哈希值技术精准清理重复文件,特别针对音频、视频和图片等多媒体文件提供了专业解决方案。通过哈希算法比对和多媒体特征识别,帮助用户高效管理存储空间,提升文件整理效率。

weixin_27032989的博客 564

aba问题mysql_Mysql事务的隔离级别,ACID以及三要素的取舍(强一致性弱一致性)、ABA问题...

一、事务的基本要素(ACID)1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A...

weixin_32155269的博客 784

Flink 作业报错——TaskManager连接不上

Flink 作业报错——TaskManager连接不上

lm223的博客 1900

PHP 并发扣款,保证数据一致性(悲观锁和乐观锁)

PHP 并发扣款,保证数据一致性(悲观锁和乐观锁) 业务场景分析 用户购买商品的逻辑中,需要对用户钱包的余额进行查询和扣款 异常:如果同一用户并发执行多个业务进行” 查询 + 扣款” 的业务中有一定概率出现数据不一致 Tips:如果没有做限制单一接口请求频率,用户使用并发请求的手段也有概率出现数据不一致 扣款场景 Step1: 从数据库查询用户钱包余额 SELECT ba...

技无涯的博客 970

[渗透测试实战篇-4] RCE漏洞组合拳突破Getshell全解析

本文深入解析RCE漏洞组合拳在渗透测试中的实战应用,通过SSRF、XXE等漏洞串联技术突破Getshell的全过程。文章详细介绍了Java和PHP环境下的漏洞利用差异,以及防御绕过与权限维持的实用技巧,为安全研究人员提供全面的实战指导。

weixin_29211309的博客 350

CESM笔记——CESM1.0-CESM1.2.2-CESM2.1.3三个版本模式工作流对比

最近测试了CESM1.0,CESM1.2.2和CESM2.1.3三个版本,不同版本在workflow上有一些区别,来做点笔记。 CESM1.0 测试compset:B_2000,F_2000 workflow: 1. create_newcase -case ~/CESM/cesm1_0/script/B_2000 -compset B_2000 -res f19_g16 -mach tianhe 2. cd B_2000 (optional) env_mach_pes.xml ##修改核数,

砍柴姑娘Jourosy的博客 4942

0719~分布式锁

redis提供的redis命令,setnx,比如三个线程同时进入一个业务,A线程进去了,只有A线程执行完释放锁后,其他两个线程才会执行;是Java用来操作redis的工具包,Redisson的宗旨是让用户redis的操作分离,为了是让用户更注重处理业务代码;概念在分布式环境下,保证某个资源在同一时间访问时,只有一个线程能访问到资源;排他锁一次只允许一个线程访问,只有等一个线程执行完后才会有下个线程进入;释放锁的原子性问题lua脚本保证原子性;乐观锁的缺点常见的ABA问题;原子性问题设置超时时间。......

m0_67574688的博客 565

人工智能训练师三级·模型生命周期真题40题|训练→评估→调优全链路通关

本文为人工智能训练师三级考试真题解析系列第2篇,聚焦模型生命周期全链路(训练→评估→调优)。内容包含40道精选真题,覆盖数据划分、模型训练、评估指标、超参数调优4个核心阶段。重点考察:1)数据集的合理划分方法(留出法、交叉验证);2)模型训练的基本原理;3)关键评估指标(准确率、召回率、F1等)的应用场景;4)超参数调优技术(网格搜索、随机搜索等)。通过真题解析帮助考生系统掌握模型生命周期的闭环迭代方法论,提升从数据准备到模型优化的全流程实践能力。适合备考人工智能训练师三级认证的考生学习参考。

白话机器学习 89

高并发下,用户余额扣减保证一致

1,可以通过队列的方式处理; 2,参见:https://m.wang1314.com/doc/webapp/topic/20483105.html 高并发下,余额扣减一致性实践 藏家004收藏于2018-11-01 转藏1次 缘起:在高并发的分布式环境下,对于数据的查询与修改容易引发一致性问题,本文将分享一种非常简单但有效的优化方法。 一、业务场景 业务场景为,购买商品的过程要对余额进行查询与修改,大致的业务流程如下: (1)从数据库查询用户现有余额 SELECT money FRO...

brazor的博客 2456

电子硬件仿真:设计一个频率范围为10k—50k的带通滤波器

带通滤波器是一种常用的滤波器类型,具有选择特定频率范围内信号的能力,并在该范围内提供一定的增益。它允许通过一定范围内的频率信号,并在该范围内提供一定的增益,同时在该范围之外的频率上提供较高的衰减。这意味着在通带内(10kHz至50kHz),滤波器的增益应为10dB,而在每个十倍频的频率点上,滤波器的增益应降低40dB。设计滤波器:使用滤波器设计工具(如MATLAB、Python的scipy库、Tina软件等),根据选定的滤波器类型(例如巴特沃斯滤波器),中心频率和通带宽度,设计一个4阶带通滤波器。

走向CTO的路上... 578

企业数字化建设之——品牌零售全渠道运营中台解决方案

OMS审单 --> 订单进入OMS待发货列表区域 --> 备货(线下)-->拣货((线下 )-->质检(线下)--> 包装(线下)--> 快递员取货(线下)(物品 + 客户收货地址清单 )--> 快递员发货(2.2.5 正常退货,客户发起 --> 客服助理审核 --> 评审组 --> ( 货物运输 ) -->质检 ->仓库收货入 正常仓库 -->财务退款,记账。OMS审单 --> 订单进入物流公司系统(如:*丰),--> 快递员发货 --> 物流状态同步OMS --> OMS同步物流状态到销售平台。

java_zhong1990的专栏 612

由并发扣款如何保证数据一致性引起的幂等性问题的思考

上一篇文章:由并发扣款如何保证数据一致性引起的ABA问题的思考 有遗漏场景,公众号 架构师之路 后续出了文章讨论了这个问题,这里附上。 1. 回顾 在上文并发扣款中的解决方案是采用CAS乐观锁,加入版本号控制。采用 select&set 方式进行余额写回: update t_account set money=#{new_money} , version=#{new_version} wh...

unclecoco的博客 661

小红书urlscheme和Activity

本文档详细介绍了小红书App的Deeplink跳转规范,涵盖了多个功能模块的跳转协议。主要内容包括:主页各Tab(关注、发现、购买)的跳转方式;不同类型笔记(图文/视频/长笔记)的详情页跳转参数;用户相关页面(主页/绑定/资料/消息等)的跳转协议;搜索功能(输入页/结果页)的跳转方式;以及话题、标签、专辑、H5页面等特殊场景的跳转实现。文档还提供了各跳转协议所需的参数说明,包括参数类型、默认值、是否必填等详细信息,并标注了不同版本和平台的兼容性要求。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 786

并发扣款一致性优化,CAS下ABA问题

程序员界的彭于晏 大家有非常多的留言,大概有这么几类: (1)是否存在ABA问题? (2)为什么不能用: UPDATE t_yue SET money=money-$diff ANDmoney>=$diff; (3)能否借助redis事务来扣减余额; 画外音:请务必阅读前序文章:《并发扣款,如何保证数据的一致性?》。 问题比较多,今天先聊第一个问题,ABA。 什么是ABA...

u011277123的博客 643

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

并发扣款,如何保证一致性?

有朋友问我:沈老师,我们有个业务,同一个用户在并发“查询,逻辑计算,扣款”的情况下,余额可能出现不一致,请问有什么优化方法么?今天和大家聊一聊这个问题。画外音:文章较长,建议提前收藏。问题一:用户扣款的业务场景是怎样的?用户购买商品的过程中,要对余额进行查询与修改,大致的业务流程如下:第一步,从数据库查询用户现有余额:SELECT money FROM t_yue WHERE uid=$uid;不...

shenjian58的博客 857

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

如何解决并发场景下扣款的数据一致性问题?

给出了并发场景下如何解决扣款一致性问题的解决方案。

每天学习一点点,每天记录一点点 834

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

先查询后修改并发的时候sql_如何解决并发场景下扣款的数据一致性问题?

1、场景介绍场景1:扣费,企业账户送流量或者红包,用户签到领取。此场景下就是多用户对某一个账号的并发扣款;场景2:充值,打赏给主播,这种场景是多用户对同一个账号进行打款,但是方案和问题和场景1是一致的。2、场景举例假设有两个业务操作同一个账号,账号余额为100,业务1扣除50,业务2扣除40,如果顺利应该是剩余100-50-40=10,那么我们看如下并发操作的场景:通过两个业务的并发操作,最后账户...

weixin_39715997的博客 903

高并发下如何保证数据的一致性

在并发量高的情况下推荐使用悲观锁的方式,如果并发量不高可以考虑使用乐观锁,但是要注意幂等性,推荐使用版本号方式。同时乐观锁场景要注意 aba 的问题。

旷野历程 1723

并发扣款一致性,幂等性问题,这个话题还没聊完!!!

《并发扣款,如何保证数据的一致性?》,分享了同一个用户并发扣款时,有一定概率出现数据不一致,可以使用CAS乐观锁的方式,在不降低吞吐量,并且只有少量修改的情况下,保证数据...

shenjian58的博客 1206

sql server 多用户 并发_如何解决并发场景下扣款的数据一致性问题?

1、场景介绍场景1:扣费,企业账户送流量或者红包,用户签到领取。此场景下就是多用户对某一个账号的并发扣款;场景2:充值,打赏给主播,这种场景是多用户对同一个账号进行打款,但是方案和问题和场景1是一致的。2、场景举例假设有两个业务操作同一个账号,账号余额为100,业务1扣除50,业务2扣除40,如果顺利应该是剩余100-50-40=10,那么我们看如下并发操作的场景:通过两个业务的并发操作,最后账户...

weixin_42538752的博客 814

架构与思维:漫谈高并发业务的CAS及ABA

高并发下的难题:支付、下单、跨行转账CAS方案以及引发的ABA问题不同维度的处理方式:应用层、数据层引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构。

sdgfafg_25的博客 1270

版本不一致_并发扣款一致性优化,CAS下ABA问题,这个话题还没聊完!!!

上一篇答星球水友提问,《并发扣款,如何保证数据的一致性?》中提到:用CAS乐观锁,可以在尽量不影响吞吐量的情况下,保证数据的一致性。大家有非常多的留言,大概有这么几类:(1)是否存在ABA问题?(2)为什么不能用:UPDATE t_yue SET money=money-$diff AND money>=$diff;(3)能否借助redis事务来扣减余额;画外音:请务必阅读前序文章...

weixin_39589557的博客 209

并发扣款

并发扣款,如何保证数据的一致性?

Hanyinh的博客 834

并发控制:确保数据一致性的策略

​ 本文主要介绍,并发扣减导致的数据不一致问题,并针对超卖、ABA 等问题提出了CAS、基于版本号的解决方案

u013911096的博客 1393

写任意正整数的次幂_并发扣款一致性,幂等性问题,这个话题还没聊完

《并发扣款,如何保证数据的一致性?》,分享了同一个用户并发扣款时,有一定概率出现数据不一致,可以使用CAS乐观锁的方式,在不降低吞吐量,并且只有少量修改的情况下,保证数据的一致性。其中,问的比较多的是ABA问题,这个问题已经在《并发扣款一致性优化,CAS下ABA问题,这个话题还没聊完!!!》中扩展。 其次,问的比较多的是作业题,为什么一定要用select&set的方式进行余额写回:UPDA...

weixin_39815031的博客 79

余额并发扣减一致性,能否使用redis事务?

《并发扣款,如何保证数据的一致性?》一文的核心观点是:使用CAS乐观锁,在写回余额时加上旧余额的比对,可以在不影响吞吐量的前提下,保证余额的一致性。文章非常多朋友留言问,...

shenjian58的博客 814
上一篇: 使用自定义注解+AOP实现RateLimiter令牌桶限流
下一篇: 由并发扣款如何保证数据一致性引起的幂等性问题的思考
可爱徐叔叔
博客等级 码龄7年 5粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值