(转)mysql处理高并发,防止库存超卖

原文链接:http://blog.csdn.net/caomiao2006/article/details/38568825

今天王总又给我们上了一课,其实mysql处理高并发,防止库存超卖的问题,在去年的时候,王总已经提过;但是很可惜,即使当时大家都听懂了,但是在现实开发中,还是没这方面的意识。今天就我的一些理解,整理一下这个问题,并希望以后这样的课程能多点。

先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购、秒杀、特价之类的活动,而这样的活动有一个共同的特点就是访问量激增、上千甚至上万人抢购一个商品。然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出现超买,以防止造成不必要的损失是众多电子商务网站程序员头疼的问题,这同时也是最基本的问题。

从技术方面剖析,很多人肯定会想到事务,但是事务是控制库存超卖的必要条件,但不是充分必要条件。

举例:

总库存:4个商品

请求人:a、1个商品 b、2个商品 c、3个商品

程序如下:

beginTranse(开启事务)

try{

$result = $dbca->query(‘select amount from s_store where postID = 12345‘);

if(result->amount > 0){

//quantity为请求减掉的库存数量

$dbca->query(‘update s_store set amount = amount - quantity where postID = 12345‘);

}

}catch($e Exception){

rollBack(回滚)

}

commit(提交事务)

以上代码就是我们平时控制库存写的代码了,大多数人都会这么写,看似问题不大,其实隐藏着巨大的漏洞。数据库的访问其实就是对磁盘文件的访问,数据库中的表其实就是保存在磁盘上的一个个文件,甚至一个文件包含了多张表。例如由于高并发,当前有三个用户a、b、c三个用户进入到了这个事务中,这个时候会产生一个共享锁,所以在select的时候,这三个用户查到的库存数量都是4个,同时还要注意,mysql innodb查到的结果是有版本控制的,再其他用户更新没有commit之前(也就是没有产生新版本之前),当前用户查到的结果依然是就版本;

然后是update,假如这三个用户同时到达update这里,这个时候update更新语句会把并发串行化,也就是给同时到达这里的是三个用户排个序,一个一个执行,并生成排他锁,在当前这个update语句commit之前,其他用户等待执行,commit后,生成新的版本;这样执行完后,库存肯定为负数了。但是根据以上描述,我们修改一下代码就不会出现超买现象了,代码如下:

beginTranse(开启事务)

try{

//quantity为请求减掉的库存数量
    $dbca->query(‘update s_store set amount = amount - quantity where postID = 12345‘);

$result = $dbca->query(‘select amount from s_store where postID = 12345‘);

if(result->amount < 0){

throw new Exception(‘库存不足‘);

}

}catch($e Exception){

rollBack(回滚)

}

commit(提交事务)

另外,更简洁的方法:

beginTranse(开启事务)

try{

//quantity为请求减掉的库存数量
    $dbca->query(‘update s_store set amount = amount - quantity where amount>=quantity and postID = 12345‘);

}catch($e Exception){

rollBack(回滚)

}

commit(提交事务)

=====================================================================================

1、在秒杀的情况下,肯定不能如此高频率的去读写数据库,会严重造成性能问题的
必须使用缓存,将需要秒杀的商品放入缓存中,并使用锁来处理其并发情况。当接到用户秒杀提交订单的情况下,先将商品数量递减(加锁/解锁)后再进行其他方面的处理,处理失败在将数据递增1(加锁/解锁),否则表示交易成功。
当商品数量递减到0时,表示商品秒杀完毕,拒绝其他用户的请求。

2、这个肯定不能直接操作数据库的,会挂的。直接读库写库对数据库压力太大,要用缓存。
把你要卖出的商品比如10个商品放到缓存中;然后在memcache里设置一个计数器来记录请求数,这个请求书你可以以你要秒杀卖出的商品数为基数,比如你想卖出10个商品,只允许100个请求进来。那当计数器达到100的时候,后面进来的就显示秒杀结束,这样可以减轻你的服务器的压力。然后根据这100个请求,先付款的先得后付款的提示商品以秒杀完。

3、首先,多用户并发修改同一条记录时,肯定是后提交的用户将覆盖掉前者提交的结果了。

这个直接可以使用加锁机制去解决,乐观锁或者悲观锁。
乐观锁,就是在数据库设计一个版本号的字段,每次修改都使其+1,这样在提交时比对提交前的版本号就知道是不是并发提交了,但是有个缺点就是只能是应用中控制,如果有跨应用修改同一条数据乐观锁就没办法了,这个时候可以考虑悲观锁。
悲观锁,就是直接在数据库层面将数据锁死,类似于oralce中使用select xxxxx from xxxx where xx=xx for update,这样其他线程将无法提交数据。
除了加锁的方式也可以使用接收锁定的方式,思路是在数据库中设计一个状态标识位,用户在对数据进行修改前,将状态标识位标识为正在编辑的状态,这样其他用户要编辑此条记录时系统将发现有其他用户正在编辑,则拒绝其编辑的请求,类似于你在操作系统中某文件正在执行,然后你要修改该文件时,系统会提醒你该文件不可编辑或删除。

4、不建议在数据库层面加锁,建议通过服务端的内存锁(锁主键)。当某个用户要修改某个id的数据时,把要修改的id存入memcache,若其他用户触发修改此id的数据时,读到memcache有这个id的值时,就阻止那个用户修改。

5、实际应用中,并不是让mysql去直面大并发读写,会借助“外力”,比如缓存、利用主从库实现读写分离、分表、使用队列写入等方法来降低并发读写。

时间: 2024-08-28 17:44:35

(转)mysql处理高并发,防止库存超卖的相关文章

mysql处理高并发,防止库存超卖

先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购一个商品.然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出现超买,以防止造成不必要的损失是众多电子商务网站程序员头疼的问题,这同时也是最基本的问题. 从技术方面剖析,很多人肯定会想到事务,但是事务是控制库存超卖的必要条件,但不是充分必要条件. 举例: 总库存:4个商品 请求人:a.1个商品 b.2个商品 c.3个商品 程序如下: beginTr

转 mysql处理高并发,防止库存超卖

原文地址: mysql处理高并发,防止库存超卖 今天王总又给我们上了一课,其实MySQL处理高并发,防止库存超卖的问题,在去年的时候,王总已经提过:但是很可惜,即使当时大家都听懂了,但是在现实开发中,还是没这方面的意识.今天就我的一些理解,整理一下这个问题,并希望以后这样的课程能多点. 先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购一个商品.然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出

Mysql在高并发情况下,防止库存超卖而小于0的解决方案

背景: 本人上次做申领campaign的PHP后台时,因为项目上线后某些时段同时申领的人过多,导致一些专柜的存货为负数(<0),还好并发量不是特别大,只存在于小部分专柜而且一般都是-1的状况,没有造成特别特别严重的后果,但还是要反思了自己的过错. 这次又有新的申领campaign,我翻看了上次的代码逻辑: 正文: [先select后update] beginTranse(开启事务) try{     $result = $dbca->query('select amount from s_st

对mysql的高并发优化配置的一些思考

对mysql的高并发优化配置的一些思考 mysql的高并发优化配置方案很多,但是适应你自己的就变得很少了,我们对数据库的优化,无非就是为了应对mysql的高并发情况罢了.随着大数据的时代的到来和网络用户的增多,很多企业中,可能每天应对的数量达百万,千万,甚至上亿的pv量,这样的量已经是超过普通配置的mysql所承受的量,所以应对日益增长的pv量,我们需要对mysql做出相应的对策,进一步优化mysql,达到我们所预期的效果,预防因为高并发所引起的mysql宕机,通过调试优化mysql,我们便可以

秒杀踩坑记:库存超卖

本案例发生在别人身上,觉得有学习借鉴的意义特转载过来记录一下. PM 说有一个类似于抢购的小需求,我们第一反应就想到是典型的防止库存超卖场景,于是理所因当地选用了 Redis 方案.只要保证是原子操作,即可防止库存超卖,自然想到使用 Incr/Decr 这类原子操作. 查看 PHP 的 Redis 扩展关于 Incr 方法的说明: /** * Increment the number stored at key by one. * * @param string $key * @return i

【转】记录PHP、MySQL在高并发场景下产生的一次事故

看了一篇网友日志,感觉工作中值得借鉴,原文如下: 事故描述 在一次项目中,上线了一新功能之后,陆陆续续的有客服向我们反应,有用户的个别道具数量高达42亿,但是当时一直没有到证据表示这是,确实存在,并且直觉告诉我们,这是不可能的,就一直没有在意,直到后来真的发现了一个用户确实是42亿,当时我们整个公司都震惊了,如果有大量用户是这样的情况,公司要亏损几十万,我们的老大告诉我们,肯定是什么地方数据溢出的,最后我们一帮人,疯了似的查代码,发现…… 如果按照正常的程序逻辑走下去,代码是完全没问题,但是我发

redis+php+mysql处理高并发实例

一.实验环境ubuntu.php.apache或nginx.mysql二.利用Redis锁解决高并发问题,需求现在有一个接口可能会出现并发量比较大的情况,这个接口使用php写的,做的功能是接收 用户的GET请求中的name字段,然后将这个字段存到mysql中,现在先将数据放到redis的队列中,然后让redis定时将这些数据转移到mysql中.二.实现步骤1.新建数据库test及 数据表test,建表语句如下 CREATE TABLE `test` ( `name` varchar(255) D

实战经验:MySQL 构建高并发网站性能优化

最近在优化一个比较大型的高并发网站,收益颇多,经验分享给大家. 1. 表字段分割.经常访问的表.行数量大的表,切记保持最少长度字段,不在select列表的数据,请做垂直分割.举例:文章表,不要将文章正文部分的内容存在文章信息表里,可以将这个字段独立存储到另一张表articleContent(articleID,articleContext).因为这个字段长度大,影响查询时的行扫描. 2. 频繁更新的字段做表的垂直分割.在做更新操作时,一般会做行锁定,有的会设置成表锁定.那么在做query的时候,

对于业务中库存超卖测试

多并发时,用相应的锁方案保证库存不发生超卖.实现这个方案后,要有相应的场景测试方案. 很多时候,验证方案非常重要. java可以利用CountDownLatch测试多并发.CountDownlatch通常用于某个业务线程需要等待其它多个线程完成某个条件后才进行相应操作. CountDownLatch有countDown及await方法,分别对应减少计数器及当计数器大于0时阻塞当前线程.当计数量等于0时所有调用await方法且被阻塞的线程都被唤醒,然后进行相应操作. 此处用于模拟10个并发用户进行