项目有需求定时删除产品,使用redis缓存产品主键,设置过期时间,到期后应用redis的键空间通知删除数据库信息。
框架是tp5.0。
redis版本是3.0.
php版本7.2
原理我不写了,首先修改配置:
打开redis配置文件redis.conf,找到notify-keyspace-events 将其设为Ex,E代表键事件通知,x代表过期事件,每当有过期键被删除时发送,然后重启redis使配置生效;
我用的是window 操作系统,redis 目录如下,
修改redis.confg 文件就可以了,但是启动的时候不能直接双击redis-server.exe 执行文件,先给大家看一下 双击之后的启动画面。开始我做的时候问题就出在这里。
这个有个警告,大致的意思是没有找到reids.conf文件 用的是默认的配置启动服务,这样的话 我们之前修改的配置就没有生效。
正确的启动方式是:
先进入reids文件夹,使用redis-server redis.conf 命令 启动服务:
这是我们之前修改的键空间配置才生效。
下面是代码部分:
//过期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('__keyevent@0__: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 下测试结果: