PHP如何實現處理過期或者超時訂單的,並還原庫存

来源:https://www.cnblogs.com/heyue0117/archive/2019/12/26/12104780.html
-Advertisement-
Play Games

訂單是我們在日常開發中經常會遇到的一個功能,最近在做一個訂單過期與超時的開發。訂單過期與超時就不用我解釋了吧,其實兩者都是同一個問題來著,就是訂單未支付的處理,我們要做的是對這些未支付的訂單到了一定時間就自動取消,好了,你第一反應那肯定就是做一個定時任務了!是的,就是定時任務,但是哪個才會是最佳方案 ...


訂單是我們在日常開發中經常會遇到的一個功能,最近在做一個訂單過期與超時的開發。訂單過期與超時就不用我解釋了吧,其實兩者都是同一個問題來著,就是訂單未支付的處理,我們要做的是對這些未支付的訂單到了一定時間就自動取消,好了,你第一反應那肯定就是做一個定時任務了!是的,就是定時任務,但是哪個才會是最佳方案呢,下麵來看看:

 

一、前端到時間請求取消

你肯定不會想著在前端來做定時請求取消該訂單的,因為如果客戶禁用了該應用或者沒聯網,那到了一定時間時,還一直都是未處理狀態的。所以前端一般都是手動去觸發取消訂單的。

 

二、服務端定時查詢有沒有需要取消的訂單,然後批量處理。

這種方法我們用得最多的,不過存在準確度的問題,還有需要確認定時任務的周期,但是我們可以結合redis來實現,我們可以在存redis時候順便存在mysql這樣的資料庫做長久存儲然後用服務端定時查詢,這裡我用到了redis的訂閱功能。

 

首先先修改一下配置

 

 然後再重啟redis

 

 這裡創建4個文件

 

 index.php  創建訂單,發佈消息,10s後查詢訂單狀態並更新訂單

<?php

require_once 'Redis2.class.php';
require_once 'db.class.php';

$redis2     = new \Redis2();
$list       = $redis2->lRange('order',0,9999999);

$mysql      = new \mysql();
$mysql->connect();

$data       = ['ordersn'=>'SN'.time().'T'.rand(10000000,99999999),'status'=>0,'createtime'=>date('Y-m-d H:i:s',time())];

$mysql->insert('order',$data);

$order_sn   = $data['ordersn'];

$redis2->setex($order_sn,10,$order_sn);

 

psubscribe.php,發佈redis訂閱的一些邏輯處理

 

 

這裡我把redis的一些操作和mysql的一些處理做了封裝處理,這個你們可以用到你們自己的項目當中的

Redis2.class.php

<?php

class Redis2
{
    private $redis;

    public function __construct($host = '127.0.0.1', $port = 6379)
    {
        $this->redis = new Redis();
        $this->redis->connect($host, $port);
        $this->redis->auth('123456');
    }

    public function setex($key, $time, $val)
    {
        return $this->redis->setex($key, $time, $val);
    }

    public function set($key, $val)
    {
        return $this->redis->set($key, $val);
    }

    public function get($key)
    {
        return $this->redis->get($key);
    }

    public function expire($key = null, $time = 0)
    {
        return $this->redis->expire($key, $time);
    }

    public function psubscribe($patterns = array(), $callback)
    {
        $this->redis->psubscribe($patterns, $callback);
    }

    public function setOption()
    {
        $this->redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
    }

    public function lRange($key,$start,$end)
    {
        return $this->redis->lRange($key,$start,$end);
    }

    public function lPush($key, $value1, $value2 = null, $valueN = null ){
        return $this->redis->lPush($key, $value1, $value2 = null, $valueN = null );
    }

    public function delete($key1, $key2 = null, $key3 = null)
    {
        return $this->redis->delete($key1, $key2 = null, $key3 = null);
    }

}

 

db.class.php,對sql處理的一些封裝

<?php
class mysql
{
    private $mysqli;
    private $result;
    /**
     * 資料庫連接
     * @param $config 配置數組
     */

    public function connect()
    {
        $config=array(
            'host'=>'127.0.0.1',
            'username'=>'root',
            'password'=>'123456qwerty',
            'database'=>'marhal',
            'port'=>3306,
            );

        $host = $config['host'];    //主機地址
        $username = $config['username'];//用戶名
        $password = $config['password'];//密碼
        $database = $config['database'];//資料庫
        $port = $config['port'];    //埠號
        $this->mysqli = new mysqli($host, $username, $password, $database, $port);

    }
    /**
     * 數據查詢
     * @param $table 數據表
     * @param null $field 欄位
     * @param null $where 條件
     * @return mixed 查詢結果數目
     */
    public function select($table, $field = null, $where = null)
    {
        $sql = "SELECT * FROM `{$table}`";
        //echo $sql;exit;
        if (!empty($field)) {
            $field = '`' . implode('`,`', $field) . '`';
            $sql = str_replace('*', $field, $sql);
        }
        if (!empty($where)) {
            $sql = $sql . ' WHERE ' . $where;
        }


        $this->result = $this->mysqli->query($sql);

        return $this->result;
    }
    /**
     * @return mixed 獲取全部結果
     */
    public function fetchAll()
    {
        return $this->result->fetch_all(MYSQLI_ASSOC);
    }
    /**
     * 插入數據
     * @param $table 數據表
     * @param $data 數據數組
     * @return mixed 插入ID
     */
    public function insert($table, $data)
    {
        foreach ($data as $key => $value) {
            $data[$key] = $this->mysqli->real_escape_string($value);
        }
        $keys = '`' . implode('`,`', array_keys($data)) . '`';
        $values = '\'' . implode("','", array_values($data)) . '\'';
        $sql = "INSERT INTO `{$table}`( {$keys} )VALUES( {$values} )";
        $this->mysqli->query($sql);
        return $this->mysqli->insert_id;
    }
    /**
     * 更新數據
     * @param $table 數據表
     * @param $data 數據數組
     * @param $where 過濾條件
     * @return mixed 受影響記錄
     */
    public function update($table, $data, $where)
    {
        foreach ($data as $key => $value) {
            $data[$key] = $this->mysqli->real_escape_string($value);
        }
        $sets = array();
        foreach ($data as $key => $value) {
            $kstr = '`' . $key . '`';
            $vstr = '\'' . $value . '\'';
            array_push($sets, $kstr . '=' . $vstr);
        }
        $kav = implode(',', $sets);
        $sql = "UPDATE `{$table}` SET {$kav} WHERE {$where}";

        $this->mysqli->query($sql);
        return $this->mysqli->affected_rows;
    }
    /**
     * 刪除數據
     * @param $table 數據表
     * @param $where 過濾條件
     * @return mixed 受影響記錄
     */
    public function delete($table, $where)
    {
        $sql = "DELETE FROM `{$table}` WHERE {$where}";
        $this->mysqli->query($sql);
        return $this->mysqli->affected_rows;
    }
}

 

對每一次訂單的訪問我們做了伺服器監聽任務,如下:

 

 

設置本地功能變數名稱並訪問http://www.startphp.cn/index.php

此時,每訪問一次index.php,就會創建一個訂單,10s鐘後,如果該訂單依舊處於未支付狀態,就設置訂單失效。

 

 

但是php的cli模式在伺服器運行後,總是會掉線,處理這個問題的方法,我們不妨寫一個腳本

1.編寫shell腳本,定時檢查進程是否存在,不存在的話就開啟服務,並且將運行情況寫入日誌

 

 

腳本文件如下:

#!/bin/sh
PIDS=`pidof php`
if [ "$PIDS" != "" ]; then
echo "在運行"
echo -e $(date +%Y"."%m"."%d" "%k":"%M":"%S)" running....." >> /mytask/task.run.log
else
echo "不在運行,開始啟動"
echo -e $(date +%Y"."%m"."%d" "%k":"%M":"%S)" start php start....." >> /mytask/task.start.log
cd /var/www/html/redis
php psubscribe.php &
echo -e $(date +%Y"."%m"."%d" "%k":"%M":"%S)" start php success....." >> /mytask/task.start.log
fi

 

在crontab任務里創建任務,這裡設定的是每5s檢查一次,crontab -e

 

 效果你可以查看task.run.log

 

 結果如下:

 

 

有需要學習交流的友人請加入交流群的咱們一起,群內都是1-7年的開發者,希望可以一起交流,探討PHP,swoole這塊的技術 或者有其他問題 也可以問,獲取swoole或者php進階相關資料私聊管理即可

別忘了點贊哦,定期分享乾貨

點此加入該群​jq.qq.com


 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Jdk8中java.time包中的新的日期時間API類的LocalDate源碼分析,TemporalAccessor、Temporal、TemporalAdjuster、ChronoLocalDate和LocalDate的關係解析。 ...
  • 要求要安裝Gin軟體包,需要:1、安裝Go(需要1.11+版本)2、設置Go工作區安裝1、下載並安裝 gin: 2、將 gin 引入到代碼中: 3、(可選)導入net/http。例如,如果使用http.StatusOK這類的常量,則需要這樣做: 快速開始1、創建一個名為 example.go 的文件 ...
  • 1、Gin 是什麼? Gin 是一個用 Go (Golang) 編寫的 HTTP web 框架。 它是一個類似於 martini 但擁有更好性能的 API 框架, 由於 httprouter,速度提高了近 40 倍。如果你需要極好的性能,使用 Gin 吧。2、為什麼要用Gin 在 Web 開發中,開 ...
  • Python web應用想要發佈使用iis發佈有兩種方式,這篇文章就為大家介紹一下這兩種方式的具體實現: 1.配置HttpPlatform程式 HttpPlatform 模塊將套接字連接直接傳遞到獨立的 Python 進程。 藉助此傳遞可根據需要運行任何 Web 伺服器,但需要用於運行本地 Web ...
  • 接下來我們來編寫第一個 Go 程式 hello.go(Go 語言源文件的擴展是 .go),代碼如下: 你也許不明白這些代碼的含義,沒關係,後面的文章里會一一說明。 代碼寫好了那我們怎麼讓代碼運行起來呢?在命令行里輸入: 此時會輸出: 前面我們配置的開發環境用的是VSCode,後面我們寫代碼都將在這裡 ...
  • 下麵列舉的是原生使用Go語言進行開發的部分項目。 1、Docker Docker 是一種操作系統層面的虛擬化技術,可以在操作系統和應用程式之間進行隔離,也可以稱之為容器。Docker 可以在一臺物理伺服器上快速運行一個或多個實例。例如,啟動一個 CentOS 操作系統,併在其內部命令行執行指令後結束 ...
  • 寫在前面:聖誕剛過,彌留者節日氣息的大家是否還在繼續學習吶~在匆忙之際也不忘給自己找幾首好聽的歌曲放鬆一下,纏繞著音樂一起來看看關於2019年流行音樂趨勢是如何用Python分析的吧! 昨天下午沒事兒,隨便聽了下音樂,結果搜到了一份數據比較好玩,所以拿了來做個數據分享案例。 這份數據是由國外比較火的 ...
  • Go語言的強項在於它適合用來開髮網絡併發方面的服務,比如消息推送、監控、容器等,所以在高併發的項目上大多數公司會優先選擇 Golang 作為開發語言。 1、Google 這個不用多做介紹,作為開發Go語言的公司,當仁不讓。Google基於Go有很多優秀的項目,比如:https://github.co ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...