php订单超时怎么做,PHP如何实现处理过期或者超时订单的,并还原库存

订单是我们在日常开发中经常会遇到的一个功能,最近在做一个订单过期与超时的开发。订单过期与超时就不用我解释了吧,其实两者都是同一个问题来着,就是订单未支付的处理,我们要做的是对这些未支付的订单到了一定时间就自动取消,好了,你第一反应那肯定就是做一个定时任务了!是的,就是定时任务,但是哪个才会是最佳方案呢,下面来看看:

一、前端到时间请求取消

你肯定不会想着在前端来做定时请求取消该订单的,因为如果客户禁用了该应用或者没联网,那到了一定时间时,还一直都是未处理状态的。所以前端一般都是手动去触发取消订单的。

二、服务端定时查询有没有需要取消的订单,然后批量处理。

这种方法我们用得最多的,不过存在准确度的问题,还有需要确认定时任务的周期,但是我们可以结合redis来实现,我们可以在存redis时候顺便存在mysql这样的数据库做长久存储然后用服务端定时查询,这里我用到了redis的订阅功能。

首先先修改一下配置

c1b9498f6dfb35f2fc75f788388eb2ed.png

然后再重启redis

82c2ad900d9108c3658f37e0d4a7ac19.png

这里创建4个文件

bf16e76b8d3612ed99c24214011b8397.png

index.php  创建订单,发布消息,10s后查询订单状态并更新订单

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订阅的一些逻辑处理

2e1b1f56c01f886d59695f257adcff64.png

这里我把redis的一些操作和mysql的一些处理做了封装处理,这个你们可以用到你们自己的项目当中的

Redis2.class.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处理的一些封装

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;

}

}

对每一次订单的访问我们做了服务器监听任务,如下:

8e7f95aa7ee986ee580a88b215960d3b.png

设置本地域名并访问http://www.startphp.cn/index.php

此时,每访问一次index.php,就会创建一个订单,10s钟后,如果该订单依旧处于未支付状态,就设置订单失效。

b9f14b5f972d2cc46a5d3e52a725a9c3.png

但是php的cli模式在服务器运行后,总是会掉线,处理这个问题的方法,我们不妨写一个脚本

1.编写shell脚本,定时检查进程是否存在,不存在的话就开启服务,并且将运行情况写入日志

f18e424209f734d8b9c1f6c968cc0993.png

脚本文件如下:

#!/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

fbb80f167d41f8ba747f11ece15f286e.png

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

8cddf63fd051f771ef9fd110b947f810.png

结果如下:

d931fb9dadcc52969c753e47bf978953.png

有需要学习交流的友人请加入交流群的咱们一起,群内都是1-7年的开发者,希望可以一起交流,探讨PHP,swoole这块的技术 或者有其他问题 也可以问,获取swoole或者php进阶相关资料私聊管理即可

别忘了点赞哦,定期分享干货

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值