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

ceb83c2ed2341220210b4b18bad270d2.png

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

一、前端到时间请求取消

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

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

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

首先先修改一下配置

74493fd4fd426e9b4ef6545656f397a4.png

然后再重启redis

1974d4c3256012327c269c71e0975f2e.png

这里创建4个文件

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

59087db61c1f59dcb661745e16b75f7f.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;

}

}

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

bd62250bdbff029d37b2dd2a9a98632d.png

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

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

e52dd9dc6229db009f7c47e273adba36.png

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

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

a1c2e0cf131c5e83d32024842acbcfd5.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

88691439bf3aff2a8bbe1ed2c67a4817.png

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

8fe8f068254e8d4dfe0c64ab13da11d8.png

结果如下:

ef65e5233d552fa29674b93fc5d2d1cd.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值