很多做过电商系统的人应该知道,我们在设计电商系统中关于商品库存扣减时,在大部分情况下(并发量不高时),商品库存都可以直接在关系型数据库中进行扣减,那么在限时抢购活动正式开始后,那些单价比平时更给力、更具吸引力的热卖商品大家肯定都会积极踊跃地参与抢购,这必然会产生大量针对数据库同一行记录的并发更新操作。因此数据库为了保证原子’性, InnoDB 引擎默认会对同一行数据记录加锁,把前端的并发请求变成串行操作,以确保数据更新时的正确性。
 
如果直接在数据库中扣减库存,应该如何避免商品超卖呢?
 
在生产环境中我们可以通过乐观锁机制来避免这个问题。所谓乐观锁,简单来说,就是在 item表中建立一个 version 字段。假设某一个热卖商品的实际库存为n,出于对性能的考虑,查询库存操作是不建议加 for update (悲观锁,代价太大)的,那么在并发场景下,必然会导致多个用户拿到的 stock 和 version都一样。因此当第1个用户成功扣减商品库存后, 需要将 item表中的 version加1, 当第 2个用户扣减库存时,由于 version 不匹配,那么无法扣减成功,并且会抛出:StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)的异常。
 
当然,对于乐观锁一般的做法,是较为友好的提醒用户:“数据已经被其他人更改,请重新操作!”。可能一般系统这种方式可行,但是对于高并发的电商系统来讲,这就非常不友好,甚至直接导致客户大面积流失,那么有没有相对较为好的解决方案呢?
 
实际上,我们可以这样干
 
为了提升库存扣减的成功率,可以适当进行重试,如果库存不足,则说明商品已经售罄,反之扣减库存后 version 继续加1 。关于在数据库中使用乐观锁扣减库存的伪代码,如下所示:
除了使用乐观锁,还可以在扣减商品库存时,利用“实际库存数 大于 扣减库存数” 作为条件来替代 version 匹配,防止商品超卖。相对于乐观锁,采用这种方式会更加
直接,由于充分利用了 InnoDB 引擎提供的行锁特性,因此大大提升和保障了库存扣减的成功率,如下所示:
 
/* 实际库存数 大于 扣减库存数*/
UPDATE item SET stock=stock - 扣减库存数 WHERE item id=l AND stock >= 扣减库存数
 
两种方案均能够有效避免商品超卖,当然还是推荐使用乐观锁的使用方案。
 
 
 
 

alibaba工程师,如何解决乐观锁冲突问题?的更多相关文章

  1. 【进阶之路】Mybatis-Plus中乐观锁@version注解的问题与解决方案

    大家好,我是练习java两年半时间的南橘,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西.知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了 ...

  2. 使用mysql乐观锁解决并发问题

    案例说明: 银行两操作员同时操作同一账户.比如A.B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户扣除50元,A先提交,B后提交.最后实际账户余额为1000 ...

  3. 使用mysql乐观锁解决并发问题思路

    本文摘自网络,仅供个人学习之用 案例说明: 银行两操作员同时操作同一账户.比如A.B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户扣除50元,A先提交,B后 ...

  4. ElasticStack系列之六 & 版本冲突处理之乐观锁

    悲观并发控制(PCC) 这一点在关系数据库中被广泛使用.假设这种情况很容易发生,我们就可以阻止对这一资源的访问.典型的例子就是当我们在读取一个数据前先锁定这一行,然后确保只有读取到数据的这个线程可以修 ...

  5. 使用MySQL乐观锁解决超卖问题

    在秒杀系统设计中,超卖是一个经典.常见的问题,任何商品都会有数量上限,如何避免成功下订单买到商品的人数不超过商品数量的上限,这是每个抢购活动都要面临的难点. 1 超卖问题描述 在多个用户同时发起对同一 ...

  6. mybatis乐观锁实现,解决并发问题

    银行两操作员同时操作同一账户就是典型的例子.比如A.B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户扣除50元,A先提交,B后提交.最后实际账户余额为100 ...

  7. Hibernate解决高并发问题之:悲观锁 VS 乐观锁

    高并发问题是程序设计所必须要解决的问题,解决此类问题最主要的途径就是对对程序进行加锁控制.hibernate对加锁机制同样做出了实现,常用加锁方式为悲观锁和乐观锁.悲观锁指的是对数据被外界(包括本系统 ...

  8. 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法

    数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...

  9. 基于Django的乐观锁与悲观锁解决订单并发问题的一点浅见

    订单并发这个问题我想大家都是有一定认识的,这里我说一下我的一些浅见,我会尽可能的让大家了解如何解决这类问题. 在解释如何解决订单并发问题之前,需要先了解一下什么是数据库的事务.(我用的是mysql数据 ...

随机推荐

  1. shiro盐值加密并验证

    在数据表中存的密码不应该是123456,而应该是123456加密之后的字符串,而且还要求这个加密算法是不可逆的,即由加密后的字符串不能反推回来原来的密码,如果能反推回来那这个加密是没有意义的.著名的加 ...

  2. JDK11和JDK8类加载器的区别

    如下代码: public class Test07 { public static void main(String[] args) throws ClassNotFoundException { / ...

  3. java5循环结构一

    public class jh_01_循环学习需要用到的知识点 { public static void main(String[] args) { int a = 1;// 把数值1赋值给int类型 ...

  4. yukongDSRM账户安全防护

    一.DSRM简介 1.DSRM(Diretcory Service Restore Mode,目录服务恢复模式)是windows域环境中域控制器的安全模式启动选项.域控制器的本地管理员账户也就是DSR ...

  5. meta的作用

    一.先明白几个概念 phys.width: device-width: 一般我们所指的宽度width即为phys.width,而device-width又称为css-width. 其中我们可以获取ph ...

  6. php连接mySql数据库 示例

    <?php header("content-type:text/html;charset=utf-8"); error_reporting(E_ALL); /* 连接数据库- ...

  7. 20200223--python学习第15天

    今日内容 模块知识 内置模块 time/datatime/json/其他 内容回顾&作业题 重点知识点 构造字典和函数对应的关系,避免重复的if  else a = 1 b = 2 ----- ...

  8. mysql 查询指定数据库所有表, 指定表所有列, 指定列所有表 所有外键及索引, 以及索引的创建和删除

    查询指定 数据库 中所有 表 (指定数据库的,所有表) // 可以把 TABLE_NAME 换成 * 号, 查看更丰富的信息 SELECT TABLE_NAME FROM information_sc ...

  9. centos6.x下yum安装heartbeat

    [root@heartbeat ~]# uname -n #<===配置heartbeat时,节点的主机名必须和 uname -n 命令的结果要一致 heartbeat [root@heartb ...

  10. [jQuery]jQuery和DOM对象(三)

    iQuery和DOM对象 用原生js获取来的对象就是DOM对象 // 1. DOM对象 var myDiv = document.get.querySelector('div'); // myDiv ...