解决并发情况下库存减为负数问题--update2016.04.24
场景:
一个商品有库存,下单时先检查库存,如果>0,把库存-1然后下单,如果<=0,则不能下单,事务包含两条sql语句:
select quantity from products WHERE id=;
update products set quantity = ($quantity-) WHERE id=;
在并发情况下,可能会把库存减为负数(两个进程同时select出来的都>0,然后都会执行update),怎么办呢?
方法1:
InnoDB支持通过特定的语句进行显示加锁:
select...lock in share mode
select...for udpate
select quantity from products WHERE id= for update;
update products set quantity = ($quantity-) WHERE id=;
但是执行for update会产生一些其他的影响
1.select语句变慢
2.一些优化无法正常使用,例如索引覆盖扫描
3.很容易造成服务器的锁争用问题
方法二:
把udpate语句写在前边,先把数量-1,之后select出库存如果>-1就commit,否则rollback。
update products set quantity = quantity- WHERE id=;
select quantity from products WHERE id= for update;
上边的事务中先执行了update,所以id=3的行被加了行锁,只有commit/rollback是才会被释放(事务中锁是逐步获得的,但是都是commit时所释放的)。很好的解决了并发问题。
方法三:
update语句在更新的同时加上一个条件
$quantity = select quantity from products WHERE id=3;
update products set quantity = ($quantity-1) WHERE id=3 and queantity = $quantity;
这样虽然select语句没有加锁,但是因为mysql的事务隔离级别是可重复读,所以其他事务的修改不会影响到select的结果,当执行到update时,如果有其他事务锁住了这条记录,update会等待,等到其他事务释放锁,update会执行,但此时如果quantity的数量已经被修改,update的执行会返回影响行数为0。
原因:
场景比如先select出来的$quantity=3,然后执行update的条件为id = 3 and quantity=3,执行更新返回影响函数为0,但再次执行select时发现id=3的记录quantity确实是3啊,怎么有这条记录却更新不了呢?
这”归功于“mysql的事物隔离级别和MVCC,当第一次select时$quantity=3,然后其他事务先于这个update执行了,导致update的条件并没有找到合适的记录,因为在可重复读级别中,update的读是“当前读”,读取的是最新的数据。而再次select时查到的$quantity还是等于3,因为对于select的读是“快照读”,读取的是历史数据,这也是可重复读级别的特性。
注意方法二中:当一个事务提交后如果库存正好是0,此时另一个事务读取到的还是1,这就是可重复读,但是由于先执行的update,update执行完之后的库存就是-1,此时再执行select的时候的结果就是-1,所以可重复读是指当前事务没有写语句的时候,如果写语句发生则是建立在其他事务提交后的结果基础上的。
详细的Innodb中的事务隔离级别可以看美团点评技术团队的一篇文章,有对于MVCC和间隙锁的解释:http://tech.meituan.com/innodb-lock.html
解决并发情况下库存减为负数问题--update2016.04.24的更多相关文章
- 利用redis实现分布式事务锁,解决高并发环境下库存扣减
利用redis实现分布式事务锁,解决高并发环境下库存扣减 问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...
- PHP通过加锁实现并发情况下抢码实现
需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: 实现: 1.在不考虑并发的情况下实现: function get_code($len){ ...
- 关于WCF服务在高并发情况下报目标积极拒绝的异常处理
最近弄了个wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好好的活着.于是开始查原因. 一般来说目标积极拒绝(TCP 10061)的异常主要是 ...
- WCF服务在高并发情况下报目标积极拒绝的异常处理 z
http://www.cnblogs.com/kklldog/p/5037006.html wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好 ...
- 并发情况下synchronized死锁
存在缺陷的代码: public class DataPropertyIdAndNameRepositoryImpl{ /** 发布标志 */ private volatile boolean publ ...
- Jackson高并发情况下,产生阻塞
情况:在高并发情况下,查看线程栈信息,有大量的线程BLOCKED. 从线程栈得知,线程栈中出现了阻塞,锁在了com.fasterxml.jackson.databind.ser.SerializerC ...
- Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载
Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...
- 高并发情况下分布式全局ID
1.高并发情况下,生成分布式全局id策略2.利用全球唯一UUID生成订单号优缺点3.基于数据库自增或者序列生成订单号4.数据库集群如何考虑数据库自增唯一性5.基于Redis生成生成全局id策略6.Tw ...
- PHP通过加锁实现并发情况下抢码功能
本文基于php语言使用加锁实现并发情况下抢码功能,特定时间段开放抢码并不允许开放的码重复: 需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: ...
随机推荐
- 【POJ 2318】TOYS 叉积
用叉积判断左右 快速读入写错了卡了3小时hhh #include<cmath> #include<cstdio> #include<cstring> #includ ...
- react.js table组件【可以直接使用】
最近在做一个CMS,使用的技术是刚刚学习的react.js,准备制作一个查询的页面以及一个新增的页面. 这是table的公共组件: 我们在使用的过程中,只会用到: 制作出来的查询页面: 新增页面: 上 ...
- VS 2013 未找到与约束contractname Microsoft.VisualStudio.Utilities.IContentTypeRegistryService...匹配的导出[vs故障]【转】
未找到与约束 contractname Microsoft.VisualStudio.Utilities.IContentTypeRegistryService RequiredTypeIdentit ...
- 史上最全最强SpringMVC详细示例实战教程
一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 1 2 3 4 5 6 ...
- gym923B
Even though he isn't a student of computer science, Por Costel the pig has started to study Graph Th ...
- Ehcache缓存配置
Cache的配置很灵活,官方提供的Cache配置方式有好几种.你可以通过声明配置.在xml中配置.在程序里配置或者调用构造方法时传入不同的参数. 你可以将Cache的配置从代码中剥离出来,也可以在使用 ...
- 【POJ 1698】Alice's Chance(二分图多重匹配)
http://poj.org/problem?id=1698 电影和日子匹配,电影可以匹配多个日子. 最多有maxw*7个日子. 二分图多重匹配完,检查一下是否每个电影都匹配了要求的日子那么多. #i ...
- Urtext的使用
UITextField 是UIControl的子类,UIControl又是UIView的子类,所以也是一个视图,只不过比UIView多了两个功能,1.文字显示,2.文本编辑 使用过程分四步: 1.创建 ...
- 【caffe】cifar10例子之quick_train.sh在windows下的解决方案
@tags caffe 照例还是转写为python脚本: import os caffe_root=os.environ['caffe_root'] caffe_build=os.environ['c ...
- oracle大数据量。表分区提示查询效率
现在业务有一张usertrack 日志记录表.每天会产生30万条数据.数据量大查询效率会非常慢 所以我考虑通过表分区来提示效率 逻辑上是一张表.但是分区后会按照分区条件将数据分在不同的物理文件 优点 ...