这次我用swoole实现订单延时,还原库存!
一、业务场景:当客户下单在指定的时间内如果没有付款,那我们需要将这笔订单取消掉,比如好的处理方法是运用延时取消,很多人首先想到的当然是crontab,这个也行,不过这里我们运用swoole的异步毫秒定时器来实现,同样也不会影响到当前程序的运行。
二、说明,order_status为1时代表客户下单确定,为2时代表客户已付款,为0时代表订单已取消(正是swoole来做的)
三、举例说明,库存表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');
下面贴出来纯手工PHP,很多同学用了原生PHP,就不会运用到框架里去,其实都一样的,不要想得那么复杂就是了。只要一点就是你用多了,你就会这样觉得咯。
配置文件config.php ,这个在框架的话,基本上都是配置好了。
<?php $dbHost = "192.168.23.110"; $dbUser = "root"; $dbPassword = "123456"; $dbName = "test"; ?>
swoole都是用在linux系统里的,这里的host你可以自己搭建虚拟主机,也可以网上购买属于自己的服务器
订单提交的文件order_submit.php,这里对订单生成,同时扣除库存的一系列操作
<?php require("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(); } ?>
订单的延时处理order_cancel.php
<?php require("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" . "end\t" . 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); } ?>
更多swoole技术文章,请访问swoole教程栏目!
以上是这次我用swoole实现订单延时,还原库存!的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Laravel 中使用 Swoole 协程可以并发处理大量请求,优势包括:并发处理:允许同时处理多个请求。高性能:基于 Linux epoll 事件机制,高效处理请求。低资源消耗:所需服务器资源更少。易于集成:与 Laravel 框架无缝集成,使用简单。

如何使用Swoole实现高性能的HTTP反向代理服务器Swoole是一款基于PHP语言的高性能、异步、并发的网络通信框架。它提供了一系列的网络功能,可以用于实现HTTP服务器、WebSocket服务器等。在本文中,我们将介绍如何使用Swoole来实现一个高性能的HTTP反向代理服务器,并提供具体的代码示例。环境配置首先,我们需要在服务器上安装Swoole扩展

Swoole 和 Workerman 都是高性能 PHP 服务器框架。Swoole 以其异步处理、出色的性能和可扩展性而闻名,适用于需要处理大量并发请求和高吞吐量的项目。Workerman 提供了异步和同步模式的灵活性,具有直观的 API,更适合易用性和处理较低并发量的项目。

要重启 Swoole 服务,请按照以下步骤操作:检查服务状态并获取 PID。使用 "kill -15 PID" 停止服务。使用启动服务的相同命令重新启动服务。

性能比较:吞吐量:Swoole 凭借协程机制,吞吐量更高。延迟:Swoole 的协程上下文切换开销更低,延迟更小。内存消耗:Swoole 的协程占用内存更少。易用性:Swoole 提供更易于使用的并发编程 API。

Swoole实战:如何使用协程进行并发任务处理引言在日常的开发中,我们常常会遇到需要同时处理多个任务的情况。传统的处理方式是使用多线程或多进程来实现并发处理,但这种方式在性能和资源消耗上存在一定的问题。而PHP作为一门脚本语言,通常无法直接使用多线程或多进程的方式来处理任务。然而,借助于Swoole协程库,我们可以使用协程来实现高性能的并发任务处理。本文将介

Swoole是一款高性能的PHP网络开发框架,借助其强大的异步机制和事件驱动特点,可以实现快速构建高并发、高吞吐的服务器应用。然而,随着业务的不断扩展和并发量的增加,服务器的CPU利用率可能会成为一个瓶颈,影响服务器的性能和稳定性。因此,在本文中,我们将介绍如何优化服务器的CPU利用率,同时提高Swoole服务器的性能和稳定性,并提供具体的优化代码示例。一、
