Laravel框架中使用Redis 进行select会改变已经存在的连接

我在用Laravel框架,然后用redis,发现如果Redis::connection('config1')通过配置文件获取的redis连接,如果进行select后,会把之前的连接库的一并改变。

'config1' => [
       'host' => 'xx',
       'password' => 'xx',
       'port' => 'xx',
       'database' => 2
]
$a = Redis::connection('config1');
$b = Redis::connection('config1');
$b->select(3);
$a->set('test1', 1);
这个时候 test1 会加到3库下

看了下源码也没看出这个是哪里的问题,到底是Laravel问题还是Predis问题呢? 我理解这个$b->select 不应该影响$a的才对啊。 请大佬赐教

Predis: 1.1.7
PHP 5.6.13
Redis Server 2.6.10
Laravel 5.4.17

阅读 2k
1 个回答

打开 \Illuminate\Support\Facades\Redis 的代码,看到 getFacadeAccessor 方法返回了 redis

image.png

然后使用 dd(get_class(app('redis'))) 可以看到, redis 是由 \Illuminate\Redis\RedisManager 来实现的。

image.png

现在打开 \Illuminate\Redis\RedisManager 的代码,找到 connection 方法。

image.png

可以清楚的看到,对于同一个名字的连接,laravel 会在首次解析后,就把它保存起来。

下次需要的时候直接返回,也就是说,同样的 name ,每次调用 connection 都是返回的同一个 Redis 实例。

image.png

这样就解释的通了吧。

那如果你非想要呢?那你可以试试 clone

$b = clone \Illuminate\Support\Facades\Redis::connection('cache');

因为一些对象被克隆后,会存在一些问题,所以类本身可以通过实现 __clone 这个魔术方法,通过将这个魔术方法设置成私有或者在内部抛异常来阻止对象实例被克隆。

就以这里的 Redis 连接为例,如果允许被克隆,其实际上也是克隆的同一个 Redis 连接而已,在同一个 Redis 连接中,任意一个对象实例发送命令势必时会影响到其他对象实例持有的同一连接,换句话说,如果你想完全区分两个对象实例,那就应该创建一个新的连接。

在这里,可以使用 resolve 方法,来创建一个新的连接,这样就不会有问题了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题