toujun007 2019-06-27 13:18:57

业务场景

一、业务场景:当客户下单在指定的时间内如果没有付款,那我们需要将这笔订单取消掉,比如好的处理方法是运用延时取消,这里我们用到了swoole,运用swoole的异步毫秒定时器不会影响到当前程序的运行,具体参考:https://wiki.swoole.com/wiki/page/319.html
二、说明,order_status为1时代表客户下单确定,为2时代表客户已付款,为0时代表订单已取消(正是swoole来做的),下面的代表我没有用框架,比较纯的PHP代表方便理解和应用
三、举例说明,库存表csdn_product_stock产品ID为1的产品库存数量为20,产品ID为2的库存数量为40,然后客户下单一笔产品ID1减10,产品ID2减20,所以库存表只够2次下单,例子中10秒后自动还原库存,如下图:

正文讲解

图解:1、第一次下完单产品ID1库存从20减到了10,产品ID2库存从40减到了20;2、第二次下完单产品ID的库存为0了,产品ID2的库存也为0了,3、第三次下单时,程序提示Out of stock;4、过了10秒钟(每个订单下单后往后推10秒),客户两次下单,由于没有付款(csdn_order表的order_status为1),产品1和产品2的库存被还原了(csdn_order表的order_status变为0),客户又可以继续下单了

1、所需要sql数据库表DROP TABLE IF EXISTS `csdn_order`;CREATE TABLE `csdn_order` (`order_id` int(10) unsigned NOT NULL AUTO_INCREMENT,`order_amount` float(10,2) unsigned NOT NULL DEFAULT '0.00',`user_name` varchar(64) CHARACTER SET latin1 NOT NULL DEFAULT '',`order_status` tinyint(2) unsigned NOT NULL DEFAULT '0',`date_created` datetime NOT NULL,PRIMARY KEY (`order_id`)) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;DROP TABLE IF EXISTS `csdn_order_detail`;CREATE TABLE `csdn_order_detail` (`detail_id` int(10) unsigned NOT NULL AUTO_INCREMENT,`order_id` int(10) unsigned NOT NULL,`product_id` int(10) NOT NULL,`product_price` float(10,2) NOT NULL,`product_number` smallint(4) unsigned NOT NULL DEFAULT '0',`date_created` datetime NOT NULL,PRIMARY KEY (`detail_id`),KEY `idx_order_id` (`order_id`)) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;DROP TABLE IF EXISTS `csdn_product_stock`;CREATE TABLE `csdn_product_stock` (`auto_id` int(10) unsigned NOT NULL AUTO_INCREMENT,`product_id` int(10) NOT NULL,`product_stock_number` int(10) unsigned NOT NULL,`date_modified` datetime NOT NULL,PRIMARY KEY (`auto_id`),KEY `idx_product_id` (`product_id`)) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;INSERT INTO `csdn_product_stock` VALUES ('1', '1', '20', '2018-09-13 19:36:19');INSERT INTO `csdn_product_stock` VALUES ('2', '2', '40', '2018-09-13 19:36:19');2、数据库配置信息:config.php<?php$dbHost = "192.168.0.110";$dbUser = "root";$dbPassword = "123456";$dbName = "test123";?>3、order_submit.php,生成订单<?phprequire("config.php");try {$pdo = new PDO("mysql:host=" . $dbHost . ";dbname=" . $dbName, $dbUser, $dbPassword, array(PDO::ATTR_PERSISTENT => true));$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);$orderInfo = array('order_amount' => 10.92,'user_name' => 'yusan','order_status' => 1,'date_created' => 'now()','product_lit' => array(0 => array('product_id' => 1,'product_price' => 5.00,'product_number' => 10,'date_created' => 'now()'),1 => array('product_id' => 2,'product_price' => 5.92,'product_number' => 20,'date_created' => 'now()')));try{$pdo->beginTransaction();//开启事务处理$sql = 'insert into csdn_order (order_amount, user_name, order_status, date_created) values (:orderAmount, :userName, :orderStatus, now())';$stmt = $pdo->prepare($sql);$affectedRows = $stmt->execute(array(':orderAmount' => $orderInfo['order_amount'], ':userName' => $orderInfo['user_name'], ':orderStatus' => $orderInfo['order_status']));$orderId = $pdo->lastInsertId();if(!$affectedRows) {throw new PDOException("Failure to submit order!");}foreach($orderInfo['product_lit'] as $productInfo) {$sqlProductDetail = 'insert into csdn_order_detail (order_id, product_id, product_price, product_number, date_created) values (:orderId, :productId, :productPrice, :productNumber, now())';$stmtProductDetail = $pdo->prepare($sqlProductDetail);$stmtProductDetail->execute(array(':orderId' => $orderId, ':productId' => $productInfo['product_id'], ':productPrice' => $productInfo['product_price'], ':productNumber' => $productInfo['product_number']));$sqlCheck = "select product_stock_number from csdn_product_stock where product_id=:productId";$stmtCheck = $pdo->prepare($sqlCheck);$stmtCheck->execute(array(':productId' => $productInfo['product_id']));$rowCheck = $stmtCheck->fetch(PDO::FETCH_ASSOC);if($rowCheck['product_stock_number'] < $productInfo['product_number']) {throw new PDOException("Out of stock, Failure to submit order!");}$sqlProductStock = 'update csdn_product_stock set product_stock_number=product_stock_number-:productNumber, date_modified=now() where product_id=:productId';$stmtProductStock = $pdo->prepare($sqlProductStock);$stmtProductStock->execute(array(':productNumber' => $productInfo['product_number'], ':productId' => $productInfo['product_id']));$affectedRowsProductStock = $stmtProductStock->rowCount();//库存没有正常扣除,失败,库存表里的product_stock_number设置了为非负数//如果库存不足时,sql异常:SQLSTATE[22003]: Numeric value out of range: 1690 BIGINT UNSIGNED value is out of range in '(`test`.`csdn_product_stock`.`product_stock_number` - 20)'if($affectedRowsProductStock <= 0) {throw new PDOException("Out of stock, Failure to submit order!");}}echo "Successful, Order Id is:" . $orderId .",Order Amount is:" . $orderInfo['order_amount'] . "。";$pdo->commit();//提交事务//exec("php order_cancel.php -a" . $orderId . " &");pclose(popen('php order_cancel.php -a ' . $orderId . ' &', 'w'));//system("php order_cancel.php -a" . $orderId . " &", $phpResult);//echo $phpResult;}catch(PDOException $e){echo $e->getMessage();$pdo->rollback();}$pdo = null;} catch (PDOException $e) {echo $e->getMessage();}?>4、order_cancel.php,这个方法主要就是做订单自动取消,并还原库存的业务处理<?phprequire("config.php");$queryString = getopt('a:');$userParams = array($queryString);appendLog(date("Y-m-d H:i:s") . "t" . $queryString['a'] . "t" . "start");try {$pdo = new PDO("mysql:host=" . $dbHost . ";dbname=" . $dbName, $dbUser, $dbPassword, array(PDO::ATTR_PERSISTENT => true));$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);swoole_timer_after(10000, function ($queryString) {global $queryString, $pdo;try{$pdo->beginTransaction();//开启事务处理$orderId = $queryString['a'];$sql = "select order_status from csdn_order where order_id=:orderId";$stmt = $pdo->prepare($sql);$stmt->execute(array(':orderId' => $orderId));$row = $stmt->fetch(PDO::FETCH_ASSOC);//$row['order_status'] === "1"代表已下单,但未付款,我们还原库存只针对未付款的订单if(isset($row['order_status']) && $row['order_status'] === "1") {$sqlOrderDetail = "select product_id, product_number from csdn_order_detail where order_id=:orderId";$stmtOrderDetail = $pdo->prepare($sqlOrderDetail);$stmtOrderDetail->execute(array(':orderId' => $orderId));while($rowOrderDetail = $stmtOrderDetail->fetch(PDO::FETCH_ASSOC)) {$sqlRestoreStock = "update csdn_product_stock set product_stock_number=product_stock_number + :productNumber, date_modified=now() where product_id=:productId";$stmtRestoreStock = $pdo->prepare($sqlRestoreStock);$stmtRestoreStock->execute(array(':productNumber' => $rowOrderDetail['product_number'], ':productId' => $rowOrderDetail['product_id']));}$sqlRestoreOrder = "update csdn_order set order_status=:orderStatus where order_id=:orderId";$stmtRestoreOrder = $pdo->prepare($sqlRestoreOrder);$stmtRestoreOrder->execute(array(':orderStatus' => 0, ':orderId' => $orderId));}$pdo->commit();//提交事务}catch(PDOException $e){echo $e->getMessage();$pdo->rollback();}$pdo = null;appendLog(date("Y-m-d H:i:s") . "t" . $queryString['a'] . "t" . "endt" . json_encode($queryString));}, $pdo);} catch (PDOException $e) {echo $e->getMessage();}function appendLog($str) {$dir = 'log.txt';$fh = fopen($dir, "a");fwrite($fh, $str . "n");fclose($fh);}?>

php date 毫秒_swoole+PHP自动取消订单he还原库存相关推荐

  1. php自动按天清空库存,swoole+PHP实现自动取消订单,还原库存等操作

    一.业务场景:当客户下单在指定的时间内如果没有付款,那我们需要将这笔订单取消掉,比如好的处理方法是运用延时取消,这里我们用到了swoole,运用swoole的异步毫秒定时器不会影响到当前程序的运行,具 ...

  2. 使用PHP+Redis实现延迟任务,实现自动取消订单功能

    简单定时任务解决方案:使用redis的keyspace notifications(键失效后通知事件) 需要注意此功能是在redis 2.8版本以后推出的,因此你服务器上的reids最少要是2.8版本 ...

  3. php redis zset 延迟队列_用PHP+Redis实现延迟任务,实现自动取消订单

    简单定时任务解决方案:使用redis的keyspace notifications(键失效后通知事件) 需要注意此功能是在redis 2.8版本以后推出的,因此你服务器上的reids最少要是2.8版本 ...

  4. php 超时支付取消订单,php利用workerman的定时器实现延时操作(订单支付不成功后一定时间未支付自动取消订单)...

    延时操作个人目前接触最多的场景是用户下单后一定时间未支付自动取消订单,传统的做法是采用定时任务定时扫描数据库超时订单或者利用客户端的请求每次请求去检测一次是否有超时订单,这些方法我始终感觉不是很好,所 ...

  5. tp5.1 PHP + Redis实现自动取消订单

    PHP + Redis实现自动取消订单 业务场景 Redis 开启 keyspace notifications tp5.1 代码实现 后台运行脚本   简单定时任务解决方案:使用redis的keys ...

  6. PHP+Redis实现延迟任务 实现自动取消订单,自动完成订单

    简单定时任务解决方案:使用redis的keyspace notifications(键失效后通知事件) 需要注意此功能是在redis 2.8版本以后推出的,因此你服务器上的reids最少要是2.8版本 ...

  7. 虾皮系统老出现服务器错误,Shopee卖家须知:虾皮系统什么状况会自动取消订单?...

    系统自动取消订单 虾皮系统什么状况会自动取消订单? ● 对卖家而言 以下三种状况,虾皮系统会自动取消订单: 1.卖家在设定的出货天数内,未申请超商寄件编号或是黑猫取件,系统将于该出货天数的隔天自动取消 ...

  8. 秒杀情况下,用户下单扣除库存创建订单之后,迟迟不付款,时间到了自动取消订单(思路)

    秒杀情况下,用户下单扣除库存创建订单之后,迟迟不付款,时间到了自动取消订单 解决方案1. 使用redis实现 1.下单之后把生成分布式全局唯一id,把订单id放进redis中,设置一个过期时间 2.定 ...

  9. Laravel自动取消订单

    最近的业务需要做15分钟内未完成支付就自动取消订单的功能,类似的功能还有很多,例如:订单完成后自动确认收货.完成付款5分钟后发送短信通知等等,这些看起来就像定时任务,即多久后去做什么事. 实现上述功能 ...

最新文章

  1. 基于TensorRT车辆实时推理优化
  2. 快速上手seajs——简单易用Seajs
  3. c#之task与thread区别及其使用
  4. java 读取控制台_Java从控制台读入数据的几种方法总结
  5. 源码安装nginx以及平滑升级
  6. 为什么要做短视频秒播优化
  7. 更换ssh通信证书,ssh更改公钥和密钥,以保证服务器安全
  8. ElasticSearch 查询最多10000条数据
  9. VS Code中powershell无法运行cnpm, vue等命令
  10. html页面加声音,HTML5 肿么给网页加屏幕点击声音。
  11. 有意思的前端代码收集
  12. php容器下安装gd库
  13. keras中sample_weight的使用
  14. 《美团机器学习实践》学习笔记:机器学习中的模型评价指标(二)——回归模型评估
  15. [Inside HotSpot] C1编译器HIR的构造
  16. 一位500强高管的忠告:怕你胸有鸿鹄之志,手无缚鸡之力
  17. 利用图像内插法放大缩小图像 Matlab
  18. java返回fail,clickhouse分析:jdbc返回failed-to-respond问题排查
  19. SpringBoot实现证书License的授权和验证
  20. 浙江大学PAT (Basic Level) Practice (中文)1014福尔摩斯的约会JAVA实现代码及分析

热门文章

  1. srs代码学习(2)- 线程模型
  2. 什么是Kibana?Kibana安装与配置(win_Elasticsearch)
  3. 大剑无锋之研发笔试题(一)
  4. Leet Code OJ 217. Contains Duplicate [Difficulty: Easy]
  5. mysql重新载入my.cnf_怎么重新加载MySQL的my.cnf?
  6. Redis持久化-数据丢失及解决
  7. css3盒模型:IE6混杂模式下的盒模型
  8. 【最新合集】编译原理习题(含答案)_11-14中间代码生成_MOOC慕课 哈工大陈鄞
  9. 大话synchronize底层原理
  10. Python数据结构学习笔记——树和图