Laravel系列-redis使用

Redis

Redis 是一个开源的 key-value 数据库。在某些场合上可以对关系型数据库进行很好的补充。Redis 的命令使用起来非常方便,例如对于字符串的存取

1
2
3
4
5
6
7
//存入字符串
127.0.0.1:6379> set name key
OK

//取出存入的字符串
127.0.0.1:6379> get name
"key"

更多的 Redis 相关的内容可以访问官网。

Laravel 中使用 Redis

Redis 可以支持诸多语言。例如 Java,Php,Ruby,Python 等。在 Laravel 中可以很方便的集成 Redis,只需要通过 Composer 安装一个扩展包就行:

1
2
3
"require": {
"predis/predis": "~1.0",
}

好了,然后就可以在 Laravel 中使用 Redis 了。可以将 Redis 当作队列来使用,也可以将 Redis 作为缓存来使用。

这些简单的用法在 Laravel 的官方文档中都可以找到很详细的文档。就不多说,今天要说的是使用过程当中的一个坑。

Redis 坑

Redis 中的发布/订阅是一个很棒的工具,有着很广的用处。但是找个特性在使用的过程中却是有些坑存在,看下面的代码:

1
2
3
4
5
6
7
8
9
 Redis::subscribe(['test-channel'], function($message) {
echo $message;
});

Route::get('publish', function () {
// Route logic...

Redis::publish('test-channel', json_encode(['foo' => 'bar']));
});

上面的代码就是 订阅模式在 Laravel 中的使用,通过一个匿名的回调函数来接收发布的消息。这里要注意的是,Redis 的订阅的命令会在后台生成一个守护进程。而 Redis 连接服务器使用的是 Socket,所以如果按照 php 的默认配置,在60秒后就会自动断开连接,订阅就没有办法继续了。所以需要在这里加一个防止超时方法,例如下面:

1
2
3
4
5
6
7
8
9
10
 ini_set('default_socket_timeout', -1); // 防止连接超时
Redis::subscribe(['test-channel'], function($message) {
echo $message;
});

Route::get('publish', function () {
// Route logic...

Redis::publish('test-channel', json_encode(['foo' => 'bar']));
});

除了上面的坑之外还有一个坑,依然看上面的代码,我做如下的修改:

1
2
3
4
5
6
7
8
9
10
 ini_set('default_socket_timeout', -1); // 防止连接超时
Redis::subscribe(['test-channel'], function($message) {
Redis::set('name', $message);
});

Route::get('publish', function () {
// Route logic...

Redis::publish('test-channel', json_encode(['foo' => 'bar']));
});

如果按照上面的写法,则会报如下的错误:

1
exception 'Predis\Response\ServerException' with message 'ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context'

找个错误的原因是在回调函数的范围内使用了 Redis::set 方法,通过看 Github 上的 issue,发现 Redis:: 生成的是同一个客户端,而在同一个客户端内,只能使用上面错误里面列出的几个命令。上面的代码里面,我使用了 Redis::set 命令,于是就报了上面的错误。解决找个问题的方法就是生成一个不同的 Redis 客户端,如下代码:

 ini_set('default_socket_timeout', -1); // 防止连接超时
 Redis::subscribe(['test-channel'], function($message) {
 			  $redisClient = new Predis\Client();
            $redisClient->set('name', $message);
 });
 
 Route::get('publish', function () {
    // Route logic...

    Redis::publish('test-channel', json_encode(['foo' => 'bar']));
});

通过上面的代码就可以解决那些问题了。

总之,Laravel 还是一个不错的框架的。

微信公众号

© 2018 ray