在目前这家公司做的第一个项目抽奖项目,要求每人每天可以有20次抽奖机会,抽奖机会可以通过多种方式获取,那么就要求每次入库增加抽奖机会的时候检测当前拥有的抽奖机会是否达到了20次,如果达到了,就不再增加机会。这里需要两个步骤

<?php
$count=query_sql("select count(*) as num from table where user_id=用户id");//统计拥有了多少机会
if($count>=20)
{
die('不增加机会');
}
query_sql("insert into table (……)");#增加一次抽奖机会
?>

很显然,先获取用户有了多少条记录,如果达到上限,不再增加,如果没达到,则增加。很简单的逻辑,可是在测试的过程中,发现并发高的情况下,总是能插入22条 23条等等,超过20条记录的。

这个问题在很多业务逻辑中都遇到了,比如商品库存控制中,获取库存数量如果数量>0则能够扣库存,然后就对库存自减,可是多个并发的情况下,就把库存扣为负数了。当然也是不合理的,说明大家都下单成功了,按道理讲不应该出现超卖的情况的。可是这样的代码总是会出现

<?php
$stock_num=query_sql("select stock_num from goods where id=商品id");//获取库存数量
if($stock_num>$buy_num)
{
query_sql("update goods set stock_num=stock_num-$buy_num where id=商品id");//数量进行扣库存
}

屡见不鲜的代码,我想各位读者也遇到过这样的逻辑的,毕竟资源总是有限的,我们肯定要多做一些判断,然而如果过分依赖这种读取的数量比较,就会造成超卖的问题。

当多个进程同时读取数据库得到的是极限的边缘的时候,大家都走进了判断分支条件中,然后发现我们都满足条件,于是大家一起入库或者操作数据库扣库存,然后呢?很明显,就超卖了!

这个问题在我的同事做的项目中也遇到了,本来每天100个库存的,前几天都是在100这个边缘就结束了很正常,结果某一天出现了121条记录,显然,大家突破了这个限制,这就让人很尴尬了,库存控制问题,非常严重,会给公司带来巨大的损失。非实物道具能够撤回或者处理,实物商品可以拒绝发货,可是仍然免不了被投诉。

这个问题如此严重,那么后来是怎么解决的呢?

我在做抽奖项目的时候,因为数据库担心并发问题,采用了redis记录获取的次数,每获取一次,redis+1,然后到达20次的时候,入库之前,先判断redis中的数量 再判断数据库中的数量,两者有一个不满足,则立即告知不可添加记录。这样就是等于把统计数量这个逻辑从数据库的统计交给了redis的统计,因为redis在原子性的操作,可以实现计数器功能应对并发的问题,这也是一个办法,只是来说减轻了数据库的责任,降低风险。

然而真的数据库层面就没有办法了吗?

我想起了平台组组长曾经说过的update语句中加where条件

<?php
$stock_num=query_sql("select stock_num from goods where id=商品id");//获取库存数量
if($stock_num>$buy_num)
{
query_sql("update goods set stock_num=stock_num-$buy_num where id=商品id and stock_num>=$buy_num");//数量进行扣库存
}

使用where子句进行对库存数量的控制,避免达到负数,这种方式能够使得SQL语句在库存不够的情况下返回false,这样就能正确的得到下单失败了。然而,对于count出来的数据如何在SQL语句中实现查询之后再更新呢?

这个问题就复杂了很多,毕竟我从来没实现过在update的语句中使用select count语句,这样的语句令人匪夷所思,但是SQL语句之所以强大,就是强大在这里,子句可以有很强大的分析功能,帮我们实现。

采用where设定子句,将子句设为表达式,避免理解为select语句,试试看

<?php
query_sql("update table set 要改字段='要改的值' where id=要改的记录id and (select count(*) from table where 条件语句)<10");//在子查询中设定某个查询条件记录总数小于上限则进行更新
?>

代码虽然可以这样写,但是会报错  ERROR 1093 (HY000): You can't specify target table  for update in FROM clause

就是说你在用update的时候不能用这样的子查询作为条件,那么我们还有其他的方法解决。给这个子查询换一个临时表不就行了吗?

update table set 要改字段='要改的值' where id=要改的记录id and (select count(*) from (select * from table table where 条件语句) as tmp)<10

这样就不会被立即为更新当前表的时候查询当前表了,因为被临时表进行了转换。或者采用网友的写法

update table,(select count(*) as num from table where 条件) as b set 要改字段='要改的值' where id=要改的记录id and b.num<10

这种方式可能更加清晰一点,能够容易理解一些,不过我还是比较喜欢我自己写出的那种方式,通过子句作为条件进行理解。

PHP mysql经典问题,防止库存把控不足问题的更多相关文章

  1. 10 个 MySQL 经典错误【转】

    Top 1:Too many connections(连接数过多,导致连接不上数据库,业务无法正常进行) 问题还原 mysql> show variables like '%max_connec ...

  2. 数据库MySQL经典面试题之SQL语句

    数据库MySQL经典面试题之SQL语句 1.需要数据库表1.学生表Student(SID,Sname,Sage,Ssex) --SID 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学 ...

  3. 【不断更新】mysql经典50道题自我练习

    mysql经典50道题自我练习 测试数据和练习题均转载自CSDN博主@启明星的指引的文章sql语句练习50题(Mysql版),用于mysql的每日自我练习 表名和字段 –1.学生表 Student(s ...

  4. MYSQL经典练习题,熟悉DQL

    MYSQL经典练习题 (本练习题可让你熟悉DQL,快速的上手DQL) 首先,先在数据库中建立基本数据库以及表项: DROP DATABASE IF EXISTS `test`; CREATE DATA ...

  5. Mysql 经典案例总结(学习之前需要有Mysql基础)01

    Sql 经典案例 gb 4.2 ** 1 检索记录 (1) 主要介绍 Sql的基本SELECT查询语句 使用 SELECT * from 表 查询数据 查询该表的每一列数据 * 代表所有的意思 也可以 ...

  6. 经典书籍---MySQL经典书籍下载

    以下是一些经典的MySQL书籍电子版,括号内为提取码,若需自取. 欢迎阅读纸质版,尊重作者版权 高性能MySQL_中文版 [ hre3 ] 高性能MySQL_英文版[ m2xj ] MySQL技术内幕 ...

  7. oracle/mysql经典电子书籍pdf下载

    Oracle LZ写的书,深入结合oracle设计.优化/SQL优化.应用层架构与优化.大量生产案例,敬请期待... Oracle编程艺术 深入理解数据库体系结构(第3版) 链接:https://pa ...

  8. 这十个MySQL经典错误

    今天就给大家列举 MySQL 数据库中,最经典的十大错误案例,并附有处理问题的解决思路和方法,希望能给刚入行,或数据库爱好者一些帮助,今后再遇到任何报错,我们都可以很淡定地去处理.学习任何一门技术的同 ...

  9. PHP解决抢购、秒杀、抢楼、抽奖等阻塞式高并发库存防控超量的思路方法

    如今在电商行业里,秒杀抢购活动已经是商家常用促销手段.但是库存数量有限,而同时下单人数超过了库存量,就会导致商品超卖甚至库存变负数的问题. 又比如:抢购火车票.论坛抢楼.抽奖乃至爆红微博评论等也会引发 ...

随机推荐

  1. Urllib3 库详解

    文档:http://urllib3.readthedocs.io/en/latest/

  2. PCL点云特征描述与提取(4)

    如何从一个深度图像(range image)中提取NARF特征 代码解析narf_feature_extraction.cpp #include <iostream> #include & ...

  3. 《C++程序设计教程——给予Visual Studio 2008》读书笔记3章

    CLR(Common Language Runtime,通用运行时),负责在执行时管理代码,提供内存管理和线程管理等核心服务,同时又确保代码的安全性和准确性.

  4. Html5學習重點清單

    SVG webSQL 數據庫 SSE 服務推送 MathML 基於xml語法 Web 存储 webSockets通信 canvas 畫布操作 音頻和視頻 地理位置 Geolocation API We ...

  5. c++ 的makefile文件实例

    首先声明, 感谢九哥的帮助,因为从来没写过makefile, 所以一直是手动编译, 然后有一次写了三个文件, 需要编译, 而我只编译了一个文件, 所以一直出错, 九哥告诉我用makefile更方便, ...

  6. WM_CONCAT字符超过4000的处理办法

    参考网址: http://stackoverflow.com/questions/11541383/ordering-by-list-of-strings-in-oracle-sql-without- ...

  7. e610. Setting Focus Traversal Keys in a Component

    When the focus is on a component, any focus traversal keys set for that component override the defau ...

  8. Objective-C MacOS以管理员权限执行程序

    在MacOS下非常多操作是须要管理员权限的, 比方我们执行chmod.在命令行下能够使用sudo chmod来申请以管理员权限执行.可是使用XCode写的程序是不能使用sudo的. 须要自己写代码来申 ...

  9. Java多线程(九)之ReentrantLock与Condition

    一.ReentrantLock 类   1.1 什么是reentrantlock   java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 ...

  10. 大爱HTML5 9款超炫HTML5最新动画源码

    我们分享过很多漂亮的HTML5动画,包括CSS3菜单.HTML5 Canvas动画等.今天我们精选了9款非常不错的超炫HTML5最新动画及其源码,一起来看看. 1.HTML5可爱的404页面动画 很逗 ...