這次我用swoole實現訂單延時,還原庫存!

這次我用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),客戶又可以繼續下單了

這次我用swoole實現訂單延時,還原庫存!

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-&gt;setAttribute(PDO::ATTR_AUTOCOMMIT,?1); ????$pdo-&gt;setAttribute(PDO::ATTR_ERRMODE,?PDO::ERRMODE_EXCEPTION); ????$orderInfo?=?array( ????????'order_amount'?=&gt;?10.92, ????????'user_name'?=&gt;?'yusan', ????????'order_status'?=&gt;?1, ????????'date_created'?=&gt;?'now()', ????????'product_lit'?=&gt;?array( ????????????0?=&gt;?array( ????????????????'product_id'?=&gt;?1, ????????????????'product_price'?=&gt;?5.00, ????????????????'product_number'?=&gt;?10, ????????????????'date_created'?=&gt;?'now()' ????????????), ????????????1?=&gt;?array( ????????????????'product_id'?=&gt;?2, ????????????????'product_price'?=&gt;?5.92, ????????????????'product_number'?=&gt;?20, ????????????????'date_created'?=&gt;?'now()' ????????????) ????????) ????); ????try{ ????????$pdo-&gt;beginTransaction();//開啟事務處理 ????????$sql?=?'insert?into?csdn_order?(order_amount,?user_name,?order_status,?date_created)?values?(:orderAmount,?:userName,?:orderStatus,?now())'; ????????$stmt?=?$pdo-&gt;prepare($sql);?? ????????$affectedRows?=?$stmt-&gt;execute(array(':orderAmount'?=&gt;?$orderInfo['order_amount'],?':userName'?=&gt;?$orderInfo['user_name'],?':orderStatus'?=&gt;?$orderInfo['order_status'])); ????????$orderId?=?$pdo-&gt;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-&gt;prepare($sqlProductDetail);?? ????????????$stmtProductDetail-&gt;execute(array(':orderId'?=&gt;?$orderId,?':productId'?=&gt;??$productInfo['product_id'],?':productPrice'?=&gt;?$productInfo['product_price'],?':productNumber'?=&gt;?$productInfo['product_number'])); ????????????$sqlCheck?=?"select?product_stock_number?from?csdn_product_stock?where?product_id=:productId";?? ????????????$stmtCheck?=?$pdo-&gt;prepare($sqlCheck);?? ????????????$stmtCheck-&gt;execute(array(':productId'?=&gt;?$productInfo['product_id']));?? ????????????$rowCheck?=?$stmtCheck-&gt;fetch(PDO::FETCH_ASSOC); ????????????if($rowCheck['product_stock_number']?prepare($sqlProductStock);?? ????????????$stmtProductStock-&gt;execute(array(':productNumber'?=&gt;?$productInfo['product_number'],?':productId'?=&gt;?$productInfo['product_id'])); ????????????$affectedRowsProductStock?=?$stmtProductStock-&gt;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?commit();//提交事務 ????????//exec("php?order_cancel.php?-a"?.?$orderId?.?"?&amp;"); ????????pclose(popen('php?order_cancel.php?-a?'?.?$orderId?.?'?&amp;',?'w')); ????????//system("php?order_cancel.php?-a"?.?$orderId?.?"?&amp;",?$phpResult); ????????//echo?$phpResult; ????}catch(PDOException?$e){ ????????echo?$e-&gt;getMessage(); ????????$pdo-&gt;rollback(); ????} ????$pdo?=?null; }?catch?(PDOException?$e)?{ ????echo?$e-&gt;getMessage(); } ?&gt;

訂單的延時處理order_cancel.php

<?php require("config.php"); $queryString = getopt(&#39;a:&#39;); $userParams = array($queryString); appendLog(date("Y-m-d H:i:s") . "t" . $queryString[&#39;a&#39;] . "t" . "start"); try {     $pdo = new PDO("mysql:host=" . $dbHost . ";dbname=" . $dbName, $dbUser, $dbPassword, array(PDO::ATTR_PERSISTENT =>?true)); ????$pdo-&gt;setAttribute(PDO::ATTR_AUTOCOMMIT,?0); ????$pdo-&gt;setAttribute(PDO::ATTR_ERRMODE,?PDO::ERRMODE_EXCEPTION); ????swoole_timer_after(10000,?function?($queryString)?{ ????????global?$queryString,?$pdo; ????????try{ ????????????$pdo-&gt;beginTransaction();//開啟事務處理 ????????????$orderId?=?$queryString['a'];?? ????????????$sql?=?"select?order_status?from?csdn_order?where?order_id=:orderId";?? ????????????$stmt?=?$pdo-&gt;prepare($sql);?? ????????????$stmt-&gt;execute(array(':orderId'?=&gt;?$orderId));?? ????????????$row?=?$stmt-&gt;fetch(PDO::FETCH_ASSOC); ????????????//$row['order_status']?===?"1"代表已下單,但未付款,我們還原庫存只針對未付款的訂單 ????????????if(isset($row['order_status'])?&amp;&amp;?$row['order_status']?===?"1")?{ ????????????????$sqlOrderDetail?=?"select?product_id,?product_number?from?csdn_order_detail?where?order_id=:orderId";?? ????????????????$stmtOrderDetail?=?$pdo-&gt;prepare($sqlOrderDetail);?? ????????????????$stmtOrderDetail-&gt;execute(array(':orderId'?=&gt;?$orderId));?? ????????????????while($rowOrderDetail?=?$stmtOrderDetail-&gt;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-&gt;prepare($sqlRestoreStock); ????????????????????$stmtRestoreStock-&gt;execute(array(':productNumber'?=&gt;?$rowOrderDetail['product_number'],?':productId'?=&gt;?$rowOrderDetail['product_id'])); ????????????????} ????????????????$sqlRestoreOrder?=?"update?csdn_order?set?order_status=:orderStatus?where?order_id=:orderId";?? ????????????????$stmtRestoreOrder?=?$pdo-&gt;prepare($sqlRestoreOrder); ????????????????$stmtRestoreOrder-&gt;execute(array(':orderStatus'?=&gt;?0,?':orderId'?=&gt;?$orderId)); ????????????} ????????????$pdo-&gt;commit();//提交事務 ????????}catch(PDOException?$e){ ????????????echo?$e-&gt;getMessage(); ????????????$pdo-&gt;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-&gt;getMessage(); } function?appendLog($str)?{ ????$dir?=?'log.txt'; ????$fh?=?fopen($dir,?"a"); ????fwrite($fh,?$str?.?"n"); ????fclose($fh); } ?&gt;

更多swoole技術文章,請訪問swoole教程欄目!

以上就是這次我用

? 版權聲明
THE END
喜歡就支持一下吧
點贊12 分享