需求:如果某个订单在某时间内还没有支付,就自动取消。
之前在公司一直都是使用Linux的定时任务,全表扫描未支付的订单,然后判断订单是否到期,如果到期了则改变订单的状态,这样一来因为使用了全表扫描,当业务量大的时候,效率会很低。
Redis应用:redis的keyspace notifications 会在key失效后发送一个事件,监听此事件的的客户端就可以收到通知(需要注意此功能是在redis 2.8版本以后推出的,因此你服务器上的reids最少要是2.8版本以上)
------------------------------开始------------------------------
先修改Redis配置(Linux系统)
打开Redis配置文件 redis.conf
把默认的
notify-keyspace-events ""
改成
notify-keyspace-events "Ex"
然后重启Redis
------------------------------代码开始------------------------------
代码我简略写了,需要什么业务逻辑根据需要写
数据表结构:
CREATE TABLE `shop_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orderid` varchar(20) NOT NULL DEFAULT '' COMMENT '订单id',
`pay` tinyint(4) NOT NULL DEFAULT '0' COMMENT '支付状态 0:未支付 1:已支付',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态 0:待支付 1:订单自动关闭',
`createtime` int(11) NOT NULL COMMENT '订单创建时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8
PHP文件名 index.php代码
try {
$dsn = 'mysql:host=127.0.0.1;dbname=shop;';
$userName = 'root';
$passWord = 'root';
$pdo = new PDO($dsn, $userName, $passWord);
$orderid = uniqid();
$createTime = time();
/*把订单信息写入MySql 需要其他信息和逻辑自己添加即可*/
$sql = "INSERT shop_order (orderid,createtime) VALUES ('$orderid','$createTime')";
$pdo->exec($sql);
/*把订单信息写入Redis 需要其他信息和逻辑自己添加即可*/
$redis = new Redis();
$redis->connect('127.0.0.1','6379');
//订单在10s后回调
$redis->setex($orderid,10,$orderid);
} catch (PDOException $e) {
die ($e->getMessage());
}
index.php的功能就是简单地把订单号写入到数据库和Redis,并且设置Redis数据的过期时间(即订单过期的时间)
PHP文件名 sub.php代码
keyevent@
ini_set('default_socket_timeout', -1);
$redis = new Redis();
$res = $redis->connect('127.0.0.1', '6379');
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
$redis->subscribe(array('__keyevent@0__:expired'), @function ($redis, $pattern, $channel, $msg){
$orderid = $channel;
echo '订单号为'.$channel.'已经过期,正在为你自动取消订单.....\r\n';
$userName = 'root';
$passWord = 'root';
$dsn = 'mysql:host=127.0.0.1;dbname=shop;';
$pdo = new PDO($dsn, $userName, $passWord);
//这个订单还没有支付并且这个订单已经到期了
$sql1 = "SELECT * FROM shop_order WHERE status = 0 and pay = 0 and orderid = '$orderid'";
$incRes = $pdo->query($sql1);
if($incRes && $incRes->rowCount()){
//把这个订单的状态设置为自动关闭状态
$sql2 = "update shop_order set `status` = 1 where orderid = '$orderid'";
$upRes = $pdo->exec($sql2);
if($upRes){
echo "订单号为:{$orderid}已取消成功....\r\n";
}
}
});
sub.php的功能就是key失效后发送一个事件,在这里收到通知,拿到订单号,设置订单的状态
测试:
先使用脚本运行sub.php
然后用浏览器运行index.php(过了几秒 Redis的某个key过期之后,我的控制台就会出现......)
订单号都拿到了, ...还有什么做不到的呢?
个人博客:https://www.521bug.cn