緩存
配置
Laravel 對(duì)多種緩存系統(tǒng)提供了統(tǒng)一的 API。緩存的配置文件存放在 config/cache.php。你可以在這個(gè)文件中指定整個(gè)應(yīng)用默認(rèn)使用何種緩存驅(qū)動(dòng)。Laravel 支持當(dāng)前主流的緩存系統(tǒng)如 Memcached 和 Redis。
緩存的配置文件也包含了一些額外的配置選項(xiàng),這些選項(xiàng)在文件中都有文檔注釋,你應(yīng)該確保自己已經(jīng)讀了這些選項(xiàng)注釋。默認(rèn)的,Laravel 配置使用 file 緩存驅(qū)動(dòng),該驅(qū)動(dòng)會(huì)在文件系統(tǒng)中存儲(chǔ)序列化的緩存對(duì)象。對(duì)于大型應(yīng)用,建議使用內(nèi)存級(jí)的緩存,如 Memcached 或者 APC。你甚至可以在 laravel 中配置多種緩存配置到相同的驅(qū)動(dòng)。
緩存先決條件
數(shù)據(jù)庫
當(dāng)使用 database 緩存驅(qū)動(dòng)時(shí),你需要建立一個(gè)表來包含這些緩存項(xiàng)。你可以根據(jù)下面的 Schema 定義來建立表文件:
Schema::create('cache', function ($table) {
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});
你也可以通過使用 php artisan cache:table Artisan 命令來生成正確的緩存表結(jié)構(gòu)遷移。
Memcached
使用 Memcached 緩存需要安裝 Memcached PECL package。
默認(rèn)的配置基于 Memcached::addServer 使用 TCP/IP:
'memcached' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100
]
],
你也可以使用 UNIX socket 路徑來設(shè)置 host。如果你這么做,你需要設(shè)置 port 為 0:
'memcached' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
Redis
在你使用 Redis 緩存之前,你需要先通過 Composer 安裝 predis/predis。
關(guān)于更多的 Redis 配置信息,你可以參考 Laravel documentation page。
緩存使用
獲取緩存實(shí)例
Illuminate\Contracts\Cache\Factory 和 Illuminate\Contracts\Cache\Repository 契約提供對(duì) Laravel 緩存服務(wù)的訪問。Factory 契約提供了應(yīng)用中所有緩存驅(qū)動(dòng)的定義。Repository 契約通常是一個(gè)基于你的 cache 配置文件所使用的默認(rèn)緩存驅(qū)動(dòng)的實(shí)現(xiàn)。
事實(shí)上,你也可以使用 Cache 假面,在這篇文檔中,我們都是使用 Cache 假面進(jìn)行舉例。Cache 假面提供了一種方便簡潔的方式來訪問 Laravel 底層緩存契約的實(shí)現(xiàn)。
例如,讓我們引入 Cache 假面到控制器:
<?php
namespace App\Http\Controllers;
use Cache;
class UserController extends Controller
{
/**
* Show a list of all users of the application.
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}
訪問多種緩存存儲(chǔ)
你可以通過 Cache 假面的 store 方法來訪問多種緩存存儲(chǔ)。傳遞到 store 方法的 key 應(yīng)該與你的 cache 配置文件中的 stores 配置項(xiàng)的列表之一相匹配:
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 10);
獲取緩存項(xiàng)
你可以通過使用 Cache 假面的 get 方法來從緩存中獲取相關(guān)項(xiàng)的值。如果該項(xiàng)在緩存中并不存在,則返回 null 。如果你需要,你也可以傳遞第二個(gè)參數(shù)到 get 方法,這個(gè)參數(shù)所傳遞的值會(huì)在緩存中項(xiàng)不存在時(shí)被返回:
$value = Cache::get('key');
$value = Cache::get('key', 'default');
你甚至可以傳遞 Closure 作為默認(rèn)值。如果緩存的項(xiàng)不存在,Closure 所返回的值將被做為默認(rèn)值。傳遞閉包的方式可以使你從數(shù)據(jù)庫或者其他外部服務(wù)中延遲獲取默認(rèn)值:
$value = Cache::get('key', function () {
return DB::table(...)->get();
});
檢查項(xiàng)是否存在
你可以使用 has 方法來檢查緩存中是否存在該項(xiàng):
if (Cache::has('key')) {
//
}
遞增/遞減項(xiàng)中的值
你可以使用 increment 和 decrement 方法來調(diào)整緩存項(xiàng)目中的整型值。這兩個(gè)方法都可以接受一個(gè)數(shù)組作為第二個(gè)參數(shù)來進(jìn)行相應(yīng)的數(shù)值調(diào)整:
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
檢索或更新緩存中的項(xiàng)
有時(shí)候,你可能希望從緩存中檢索出一個(gè)項(xiàng)目,但是當(dāng)該項(xiàng)不存在的時(shí)候,你也想存儲(chǔ)一個(gè)默認(rèn)值到該項(xiàng)。比如,你希望從緩存中檢索出一個(gè)用戶。但是他并不存在,所以你需要從數(shù)據(jù)庫中獲取到他,然后添加到緩存中。你可以使用 Cache::remember 方法來做到這些:
$value = Cache::remember('users', $minutes, function () {
return DB::table('users')->get();
});
如果緩存中沒有檢索到該項(xiàng),傳遞到 remeber 方法中的閉包將會(huì)被執(zhí)行并且其執(zhí)行結(jié)果將會(huì)在緩存中進(jìn)行替換。
你也可以合并 remember 和 forever 方法:
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
檢索并刪除
如果你需要檢索一個(gè)項(xiàng)目,并在檢索到的同時(shí)從緩存中刪除該項(xiàng),你可以使用 pull 方法。就像 get 方法一樣,如果未檢索到該項(xiàng),將會(huì)返回 null :
$value = Cache::pull('key');
存儲(chǔ)項(xiàng)目到緩存
你可以使用 Cache 假面的 put 方法來存儲(chǔ)項(xiàng)目到緩存中。當(dāng)你存儲(chǔ)一個(gè)項(xiàng)到緩存中時(shí),你需要指定一個(gè)該項(xiàng)需要被緩存的分鐘值:
Cache::put('key', 'value', $minutes);
除了傳遞一個(gè)數(shù)值作為緩存過期的分鐘值,你也可以通過傳遞一個(gè) PHP DateTime 實(shí)例來設(shè)置緩存的失效時(shí)間:
$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);
add 方法只會(huì)在相應(yīng)的項(xiàng)在緩存中不存在時(shí)才會(huì)被添加進(jìn)緩存。該方法會(huì)在項(xiàng)目被添加到緩存后返回 true。否則返回 false:
Cache::add('key', 'value', $minutes);
forever 方法可以用來將項(xiàng)目永久的添加進(jìn)緩存。該值只有手動(dòng)的使用 forget 方法才能被移除:
Cache::forever('key', 'value');
從緩存中移除項(xiàng)目
你可以使用 Cache 假面的 forget 方法來從緩存中移除某項(xiàng):
Cache::forget('key');
你可以使用 flush 方法來擦除所有的緩存:
Cache::flush();
擦除緩存并不會(huì)根據(jù)前綴來進(jìn)行智能擦除,它會(huì)移除所有的緩存。所以如果你的應(yīng)用和其他的應(yīng)用共享緩存,你應(yīng)該謹(jǐn)慎的使用該方法。
緩存標(biāo)簽
注意: 緩存標(biāo)簽并不支持
file或者database緩存驅(qū)動(dòng)。另外,對(duì)于將多種標(biāo)簽標(biāo)記為永久存儲(chǔ)的驅(qū)動(dòng),性能最好的是能夠提供自動(dòng)清除過期記錄的驅(qū)動(dòng),比如memcached。
存儲(chǔ)標(biāo)記了的項(xiàng)目到緩存
緩存標(biāo)簽允許你將相關(guān)的項(xiàng)目進(jìn)行關(guān)聯(lián)標(biāo)記。并且允許一次性清除所有給定標(biāo)簽的緩存項(xiàng)。你可以通過有序的標(biāo)簽數(shù)組來訪問被標(biāo)記的緩存項(xiàng)目。比如,讓我們?cè)L問被標(biāo)記的項(xiàng)目并使用 put 方法來設(shè)置緩存值:
Cache::tags(['people', 'artists'])->put('John', $john, $minutes);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);
事實(shí)上,你并沒有被限制只使用 put 方法。你可以在標(biāo)簽中使用任意的緩存存儲(chǔ)方法。
訪問被標(biāo)記的緩存項(xiàng)
為了訪問被標(biāo)記了的緩存項(xiàng),你需要傳遞相應(yīng)的有序列表到 tags 方法:
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
你可以一次性的擦除分配的標(biāo)記或者標(biāo)記列表中的所有項(xiàng)。比如,你可以使用 flush 方法來刪除所有的 people 和 authors 標(biāo)簽和兩者組成的有序列標(biāo)簽里的所有緩存項(xiàng)。所以,Anne 和 John 都會(huì)被從緩存中移除:
Cache::tags(['people', 'authors'])->flush();
下面的語句將會(huì)作為上面語句的對(duì)照,將只會(huì)從緩存中刪除 authors 標(biāo)簽的項(xiàng)目,所以 Anne 會(huì)被刪除,而 John 被保留:
Cache::tags('authors')->flush();
添加自定義的緩存驅(qū)動(dòng)
為了在自定義的緩存驅(qū)動(dòng)中繼承 laravel 的緩存。我們需要使用 Cache 假面的 extend 方法,該方法被用來綁定自定義緩存到底層管理中。通常這些都是在服務(wù)提供者中完成。
比如,注冊(cè)一個(gè)新的緩存驅(qū)動(dòng)并命名為 'mongo':
<?php
namespace App\Providers;
use Cache;
use App\Extensions\MongoStore;
use Illuminate\Support\ServiceProvider;
class CacheServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
}
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
}
第一個(gè)被傳遞到 extend 方法中的參數(shù)應(yīng)該是驅(qū)動(dòng)的名稱。這個(gè)名稱應(yīng)該和你的 config/cache.php 配置文件中的 driver 選項(xiàng)一致。而第二個(gè)參數(shù)是一個(gè)閉包,該閉包應(yīng)該返回一個(gè) Illuminate\Cache\Repository 的實(shí)現(xiàn)。在閉包中將會(huì)被傳遞一個(gè) $app 實(shí)例,這個(gè)實(shí)例是 laravel 中的服務(wù)容器的實(shí)例。
Cache::extend 方法的調(diào)用應(yīng)該在 App\Providers\AppServiceProvider 的 boot 方法中完成?;蛘吣憧梢詣?chuàng)建自己的服務(wù)提供者來存儲(chǔ)這個(gè)擴(kuò)展。但是不要忘記在 config/app.php 文件中進(jìn)行注冊(cè)。
為了創(chuàng)建我們自己的緩存驅(qū)動(dòng),我們首先需要實(shí)現(xiàn) Illuminate\Constracts\Cache\Store 契約的接口。所以,我們的 MongoDB 緩存實(shí)現(xiàn)應(yīng)該看起來像這樣:
<?php
namespace App\Extensions;
class MongoStore implements \Illuminate\Contracts\Cache\Store
{
public function get($key) {}
public function put($key, $value, $minutes) {}
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
public function getPrefix() {}
}
我們僅僅需要使用 MongoDB 連接來實(shí)現(xiàn)這些方法。一旦我們的實(shí)現(xiàn)完成,我們就可以完成自己的緩存驅(qū)動(dòng)的注冊(cè):
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
然后在 config/cache.php 配置文件中更新驅(qū)動(dòng)為的名稱 driver 為你的擴(kuò)展的名稱。
如果你在為自定義的緩存文件應(yīng)該存放在哪里而疑惑,你可以考慮將其發(fā)布到 Packagist!或者,你可以在 app 目錄中創(chuàng)建一個(gè) Extensions 命名空間。事實(shí)上,你應(yīng)該謹(jǐn)記,laravel 并不死板的限制你的目錄結(jié)構(gòu),你應(yīng)該可以根據(jù)自己的習(xí)慣自由的管理你的應(yīng)用目錄結(jié)構(gòu)。
事件
如果你想在任何緩存被操作時(shí)執(zhí)行額外的代碼,你可能需要監(jiān)聽緩存的觸發(fā)事件。通常的你應(yīng)該存放這些事件監(jiān)聽器到你的 EventServiceProvider:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\LogCacheHit',
],
'Illuminate\Cache\Events\CacheMissed' => [
'App\Listeners\LogCacheMissed',
],
'Illuminate\Cache\Events\KeyForgotten' => [
'App\Listeners\LogKeyForgotten',
],
'Illuminate\Cache\Events\KeyWritten' => [
'App\Listeners\LogKeyWritten',
],
];