redis 键空间通知 php tp5.0版本

项目有需求定时删除产品,使用redis缓存产品主键,设置过期时间,到期后应用redis的键空间通知删除数据库信息。

框架是tp5.0。

redis版本是3.0.

php版本7.2

原理我不写了,首先修改配置:

打开redis配置文件redis.conf,找到notify-keyspace-events 将其设为Ex,E代表键事件通知,x代表过期事件,每当有过期键被删除时发送,然后重启redis使配置生效;

我用的是window 操作系统,redis 目录如下,

redis 键空间通知 php tp5.0版本

修改redis.confg 文件就可以了,但是启动的时候不能直接双击redis-server.exe 执行文件,先给大家看一下 双击之后的启动画面。开始我做的时候问题就出在这里。

redis 键空间通知 php tp5.0版本

这个有个警告,大致的意思是没有找到reids.conf文件 用的是默认的配置启动服务,这样的话 我们之前修改的配置就没有生效。

正确的启动方式是:

redis 键空间通知 php tp5.0版本

先进入reids文件夹,使用redis-server redis.conf 命令 启动服务:

redis 键空间通知 php tp5.0版本

这是我们之前修改的键空间配置才生效。

下面是代码部分:

//过期redis封装类
class ExpireRedis
{
    private $redis;
    private $key;

    public function __construct($id = 0)
    {
        $this->redis = BaseRedis::getinstance(); //这里使用单例模式连接redis
        $this->redis->select(0);
        $this->key = 'test:expire:'.$id;
    }

    public function setex( $time, $val)
    {
        return $this->redis->setex($this->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);
    }

}

这里我使用观察者模式,当用户添加产品的时候 通知Expire类  查询用户的删除策略,然后生成redis键 

use SplSubject;

class Expire implements \SplObserver{
    //自动删除基础单位时间  一天
    //const BASE_TIME = 60*60*24;
    const BASE_TIME = 10; //测试 基础单位为10秒
    protected $redis;

    public function update(SplSubject $subject)
    {
        //添加产品 状态1的时候 代表添加产品
        if ($subject->status == 1) { 
            $pid = $subject->pid;
            $datas = $subject->getProductItem();
            $userId = $datas['uid'];
            //查询用户设置的删除策略
            $userInfoItem = UserInfoModel::where(['uid'=>$userId])->field('auto_del')->find();
            $auto_del = $userInfoItem['auto_del'];

            $this->redis = new ExpireRedis($pid);
            switch ($auto_del){
                case 1:
                    $value = self::BASE_TIME * 7;
                    break;
                case 2:
                    $value = self::BASE_TIME * 30;
                    break;
                case 3:
                    $value = self::BASE_TIME * 90;
                    break;
                case 4:
                    $value = self::BASE_TIME * 180;
                    break;
                case 5:
                    $value = self::BASE_TIME * 365;
                    break;
                case 6:
                    $value = self::BASE_TIME * 730;
                    break;
                default:
                    $value = 10;
            }
            $this->redis->setex($value,$pid);
        }
    }
}

 然后使用tp5的自定义命令,创建删除产品的命令

class DelProduct extends Command
{

    protected function configure() {
        $this->setName('del')->setDescription('定时删除产品');
    }

    protected function execute(Input $input, Output $output)
    {
        $redis = new ExpireRedis();
        $redis->setOption();
        $redis->psubscribe(array('[email protected]__:expired'),array($this,'psubscribe'));
    }

    public  function psubscribe ($redis, $pattern, $chan, $msg){

        $msgItem = explode(':',$msg);
        $pid = $msgItem[2];  // 这里取产品的ID

        //这里操作数据库删除产品

        echo "修改产品ID:".$pid.'成功!'.PHP_EOL;
     }
}

然后在linux服务器项目文件夹下 守护进程下执行  nohup php think del &  

我的本地是windows系统,没有使用liunx 环境。

windows 下测试结果:

redis 键空间通知 php tp5.0版本