前兩篇文章都有提到這個cache和session選擇redis作為存儲機(jī)制的時候遇到的一些問題,今天這里著重說明下。先看下我的database.php中關(guān)于redis的配置:
'redis' => array(
'cluster' => false,
'default' => array(
'host' => '192.168.1.120',
'port' => 6379,
'database' => 0,
),
'cache' => array(
'host' => '192.168.1.120',
'port' => 6379,
'database' => 1,
),
'session' => array(
'host' => '192.168.1.120',
'port' => 6379,
'database' => 2,
),
),
我這么配置的意圖就是想在緩存的時候使用cache這個配置項,session的數(shù)據(jù)存儲在session這個配置項。那么我們先來看下我在app/config/cache.php中的相關(guān)配置
'driver' => 'redis',
'path' => storage_path().'/cache',
'connection' => 'cache',
然后再來看下我在app/config/session.php中的相關(guān)配置
'driver' => 'redis',
'files' => storage_path().'/sessions',
'connection' => 'session',
這里我把兩者的驅(qū)動都設(shè)置為redis。經(jīng)過對以上的設(shè)置進(jìn)行測試,發(fā)現(xiàn)一個問題:session的數(shù)據(jù)可以正常存儲到指定的服務(wù)中,而cache的數(shù)據(jù)并沒有按照預(yù)期的進(jìn)行了存儲,而是存儲在了session的服務(wù)中。
這是為什么呢?請繼續(xù)往下看?,F(xiàn)在我們換種方法,我們稍微修改下上面的配置,我們把session的驅(qū)動改成非redis,比如memcache等,這時我們再進(jìn)行測試,效果如下:緩存的數(shù)據(jù)存儲到了default上面,并非我們期望的cache服務(wù)。
這又是為什么呢?通過上面我們發(fā)現(xiàn)了兩個問題,暫且按順序叫問題A和問題B吧。這里我們先來解決問題B。問題B的產(chǎn)生原因是laravel的cache并不支持redis的connection(也就是說當(dāng)緩存的驅(qū)動是redis時,connection的設(shè)置沒有意義的),只有database驅(qū)動時才支持,那么我們怎么改,才能支持呢?,修改起來很簡單。既然是cache那么肯定找cacheManager了: Laravel/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php修改一下方法的代碼為一下:
/**
* Create an instance of the Redis cache driver.
*
* @return \Illuminate\Cache\RedisStore
*/
protected function createRedisDriver()
{
$redis = $this->app['redis'];
// 增加一行獲取cache connection值的代碼
$connection = $this->app['config']['cache.connection'];
// 為RedisStore設(shè)置第三個參數(shù)
return $this->repository(new RedisStore($redis, $this->getPrefix(), $connection));
}
OK,改完了,是不是很簡單呢。這樣子一改,就能解決我們的問題B,可以保證當(dāng)我們的cache的驅(qū)動為redis時,緩存的數(shù)據(jù)是存在connection(cache)指定的服務(wù)中的。那么我們這樣子改了之后能否解決A問題呢?很抱歉,不能?。?!那按照醬紫我測試了下,結(jié)果還是跟上面沒改之前的結(jié)果一樣(session的數(shù)據(jù)可以正常存儲到指定的服務(wù)中,而cache的數(shù)據(jù)并沒有按照預(yù)期的進(jìn)行了存儲,而是存儲在了session的服務(wù)中。)目前我還沒有發(fā)現(xiàn)有好的解決方案,為什么,請看下面分析。其實我們大家都知道,session其實也一種緩存,那么既然是一種緩存,那么肯定是按照緩存的流程來處理的(其實laravel的部分session驅(qū)動(redis,memcache,memcached)走的就是緩存的存儲流程)具體來看代碼:文件是:Laravel/vendor/laravel/framework/src/Illuminate/Session/SessionManager.php
/**
* Create an instance of the Redis session driver.
*
* @return \Illuminate\Session\Store
*/
protected function createRedisDriver()
{
// 這里會設(shè)置當(dāng)前redis的connection為cache
$handler = $this->createCacheHandler('redis');
// 這里會設(shè)置當(dāng)前redis的connection為session(也就是說覆蓋了上面的)
$handler->getCache()->getStore()->setConnection($this->app['config']['session.connection']);
return $this->buildSession($handler);
}
這段代碼是在應(yīng)用啟動的時候通過booting callbacks啟動session時調(diào)用的一個方法,這個方法的功能是創(chuàng)建一個redis的session驅(qū)動。我們不妨看下createCacheHandler這個方法:
/**
* Create the cache based session handler instance.
*
* @param string $driver
* @return \Illuminate\Session\CacheBasedSessionHandler
*/
protected function createCacheHandler($driver)
{
$minutes = $this->app['config']['session.lifetime'];
// 這里最終會調(diào)用下面的CacheManager的createRedisDriver方法
return new CacheBasedSessionHandler($this->app['cache']->driver($driver), $minutes);
}
我們來看下CacheManager的createRedisDriver方法文件是: Laravel/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php
/**
* Create an instance of the Redis cache driver.
*
* @return \Illuminate\Cache\RedisStore
*/
protected function createRedisDriver()
{
$redis = $this->app['redis'];
$connection = $this->app['config']['cache.connection'];
// 這里我們設(shè)置我們cache的redis connection
return $this->repository(new RedisStore($redis, $this->getPrefix(), $connection));
}
這段代碼是我們改過之后的代碼,但是沒關(guān)系。通過上面的分析,我們發(fā)現(xiàn),其實在cache和session同時使用一個驅(qū)動的時候最終的驅(qū)動是由session的配置文件中的connection值決定的,因為它覆蓋了cache設(shè)定的驅(qū)動值。那么造成這個問題的原因就是我們上面說的,session的所有數(shù)據(jù)處理是根據(jù)cache的流程處理的,因為session也是一種cache。=.=其實這個要說是個問題,其實也是個問題,因為它沒有按照我們的要求進(jìn)行處理。要是不是個問題,其實也不是個問題,因為session從某種意義上來說也是緩存,當(dāng)然后面設(shè)置的覆蓋了前面設(shè)置的。那么有沒有辦法解決呢?提供兩個側(cè)面的解決方案:1:兩者不要同時使用一種驅(qū)動,可以交替者。比如cache用memcache,session用redis等。2:就是用上次我提到的方案:
$redisCache = App::make('cache'); // Assumes "redis" set as your cache
$redisCache->setConnection('cache'); // Your redis cache connection
$redisCache->put('testtCacheIndex', 'fbbinValue', 10000);
// 或者
$redis = Redis::connection('cache');
$redis->set('fbbin', 'fbbinValue');
var_dump($redis->get('fbbin'))