thinkphp+redis实现超时取消订单功能

业务场景:秒杀案例

秒杀业务逻辑:多个用户同时抢单,通过mysql行锁抢到的用户进入待支付页面(倒计时)。当用户没有支付订单超时时则取消该订单并归还库存。

应用:

thinkphp+redis+workerman(可以自定义命令常驻)

1、thinkphp安装workerman。这里就过了,thinkphp手册去找。

2、安装好redis及扩展。用宝塔的直接搞就完了,过。

3、生产者:用户创建订单向redis插入一条订单数据。


$redis = new \Redis();
$redis->connect('127.0.0.1',6379);
//$redis->auth('密码');//redis有密码就加
/**
*seckill_time为列队名称
*time() + $seckill['pay_time']为到期时间戳
*$newSeckillOrder->id为订单id,可以json字符串存储
*/
$redis->zAdd('seckill_time', time() + $seckill['pay_time'], $newSeckillOrder->id);

4、消费者:这里我们需要一个常驻内存一直来查询这个列队是否有消息,如果有就消费掉。

workerman

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
        //防止时间出问题
        date_default_timezone_set('PRC');

        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        //redis密码
        //$redis->auth('密码');//redis有密码就加此句

        if($worker->id === 0){
            //其他任务
        }
        //秒杀处理进程
        if($worker->id === 1){
            echo "启动秒杀任务!\n";
            //workerman定时器,每秒执行一次。
            Timer::add(1, function() use($redis) {
                //通过zRangeByScore查询seckill_time列队中0到当前时间戳的数据。
                $res = $redis->zRangeByScore('seckill_time', 0, time());
                //存在数据
                if (count($res) > 0) {
                    foreach ($res as $k=>$v){
                        //处理订单,$res[$k]为生产者存的订单id或数据。
                        //.....
                        //消费掉列队中的行数据
                        $redis->zRem('seckill_time', $res[$k]);
                    }
                    //这步不用说都懂的吧!毕竟常驻内存,我们要管理好内存哦~
                    unset($res);
                }
            });
        }



    }

测试结果:

cfcd743c36374210b56b928aaa70ccd4.png

 我这边是延迟20秒消费

如下:

f2a405d41d274673ab195397d97365b4.png

 消费掉后列队就空了哦~

使用该方案的原因:

可能有些人会问,workerman有定时器,可以直接延迟操作呀?为什么如此多此一举脱裤子放屁呢?

 

原因很简单,如果workerman突然出问题掉了,那定时器延迟的一些数据是不是就终止了呢?这样会导致丢掉的数据无法去关闭订单啦!所以采用redis延迟消息列队,将数据存入redis中,即使workerman出问题掉了,重新启动workerman也可以将没消费的数据消费掉!

关于redis重启丢数据问题需要修改配置如下。

找到appendonly no 改为 appendonly yes
找到appendfsync 设置为 appendfsync everysec

解决redis重启了就丢数据的问题。

当然也可以使用其他的消息中间件来解决,比如mq,不过对于宝塔用户安装简介还是redis吧!

记住!不要定时器循环查数据库判断!不要定时器循环查数据库判断!不要定时器循环查数据库判断!

说三遍,数据库压力很大的~

当然该方案也适用拼团到期自动关闭该团等,自行脑补。

 

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
好的,下面是ThinkPHP6实现Redis连接池以及Redis队列的详细代码实现。 首先,在ThinkPHP6中使用Redis需要安装`topthink/think-redis`扩展,可以通过以下命令进行安装: ``` composer require topthink/think-redis ``` 接下来,我们需要在项目的配置文件中配置Redis连接信息,可以在`config/database.php`文件中添加以下代码: ```php 'redis' => [ 'type' => 'redis', 'hostname' => '127.0.0.1', 'password' => '', 'port' => 6379, 'select' => 0, 'timeout' => 0, 'prefix' => '', 'persistent' => true, 'pool' => [ 'min_connections' => 1, 'max_connections' => 10, 'wait_timeout' => 3, 'max_idle_time' => 60, ], ], ``` 配置项说明: - `type`:数据库类型,这里填写`redis`。 - `hostname`:Redis主机地址。 - `password`:Redis密码,如果没有设置密码可以不填写。 - `port`:Redis端口号,默认为6379。 - `select`:选择的数据库,默认为0。 - `timeout`:连接Redis超时时间,默认为0表示不限制。 - `prefix`:设置的键名前缀,默认为空。 - `persistent`:是否使用持久化连接,默认为true。 - `pool`:配置连接池信息,包括最小连接数、最大连接数、等待超时时间和最大空闲时间。 接下来,我们可以通过以下代码获取Redis连接并进行操作: ```php use think\facade\Cache; // 获取Redis连接 $redis = Cache::store('redis')->handler(); // 设置键值对 $redis->set('name', 'Tom'); // 获取键值对 $name = $redis->get('name'); echo $name; ``` 以上代码中,我们使用了ThinkPHP6的缓存门面`think\facade\Cache`来获取Redis连接,通过`store`方法指定使用`redis`缓存驱动,再通过`handler`方法获取Redis连接。 接下来,我们来实现Redis队列功能,具体的代码如下: ```php use think\queue\Job; use think\facade\Cache; // 定义任务处理类 class TestJob { public function fire(Job $job, $data) { // 获取Redis连接 $redis = Cache::store('redis')->handler(); // 从队列中取出任务数据 $name = $data['name']; // 进行任务处理 // ... // 任务处理完成后删除任务 $job->delete(); } } // 将任务加入队列 $jobHandlerClassName = 'TestJob'; // 任务处理类名 $jobData = ['name' => 'Tom']; // 任务数据 $queueName = 'test_queue'; // 队列名称 $delay = 0; // 延迟时间,默认为0 \think\Queue::later($delay, $jobHandlerClassName, $jobData, $queueName); ``` 以上代码中,我们首先定义了一个任务处理类`TestJob`,它实现了`fire`方法来处理任务。在`fire`方法中,我们首先获取Redis连接,然后从队列中取出任务数据,进行任务处理,并最终删除任务。 接下来,我们将任务加入队列。在代码中,我们使用了`think\Queue`门面的`later`方法来将任务加入队列,指定了任务处理类名、任务数据、队列名称和延迟时间(默认为0表示不延迟)。 以上就是ThinkPHP6实现Redis连接池和Redis队列的详细代码实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一码超人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值