緩存
配置
Laravel 對多種緩存系統(tǒng)提供了統(tǒng)一的 API。緩存的配置文件存放在 config/cache.php
。你可以在這個文件中指定整個應(yīng)用默認(rèn)使用何種緩存驅(qū)動。Laravel 支持當(dāng)前主流的緩存系統(tǒng)如 Memcached 和 Redis。
緩存的配置文件也包含了一些額外的配置選項,這些選項在文件中都有文檔注釋,你應(yīng)該確保自己已經(jīng)讀了這些選項注釋。默認(rèn)的,Laravel 配置使用 file
緩存驅(qū)動,該驅(qū)動會在文件系統(tǒng)中存儲序列化的緩存對象。對于大型應(yīng)用,建議使用內(nèi)存級的緩存,如 Memcached 或者 APC。你甚至可以在 laravel 中配置多種緩存配置到相同的驅(qū)動。
緩存先決條件
數(shù)據(jù)庫
當(dāng)使用 database
緩存驅(qū)動時,你需要建立一個表來包含這些緩存項。你可以根據(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。
緩存使用
獲取緩存實例
Illuminate\Contracts\Cache\Factory
和 Illuminate\Contracts\Cache\Repository
契約提供對 Laravel 緩存服務(wù)的訪問。Factory
契約提供了應(yīng)用中所有緩存驅(qū)動的定義。Repository
契約通常是一個基于你的 cache
配置文件所使用的默認(rèn)緩存驅(qū)動的實現(xiàn)。
事實上,你也可以使用 Cache
假面,在這篇文檔中,我們都是使用 Cache
假面進(jìn)行舉例。Cache
假面提供了一種方便簡潔的方式來訪問 Laravel 底層緩存契約的實現(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');
//
}
}
訪問多種緩存存儲
你可以通過 Cache
假面的 store
方法來訪問多種緩存存儲。傳遞到 store
方法的 key 應(yīng)該與你的 cache
配置文件中的 stores
配置項的列表之一相匹配:
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 10);
獲取緩存項
你可以通過使用 Cache
假面的 get
方法來從緩存中獲取相關(guān)項的值。如果該項在緩存中并不存在,則返回 null
。如果你需要,你也可以傳遞第二個參數(shù)到 get
方法,這個參數(shù)所傳遞的值會在緩存中項不存在時被返回:
$value = Cache::get('key');
$value = Cache::get('key', 'default');
你甚至可以傳遞 Closure
作為默認(rèn)值。如果緩存的項不存在,Closure
所返回的值將被做為默認(rèn)值。傳遞閉包的方式可以使你從數(shù)據(jù)庫或者其他外部服務(wù)中延遲獲取默認(rèn)值:
$value = Cache::get('key', function () {
return DB::table(...)->get();
});
檢查項是否存在
你可以使用 has
方法來檢查緩存中是否存在該項:
if (Cache::has('key')) {
//
}
遞增/遞減項中的值
你可以使用 increment
和 decrement
方法來調(diào)整緩存項目中的整型值。這兩個方法都可以接受一個數(shù)組作為第二個參數(shù)來進(jìn)行相應(yīng)的數(shù)值調(diào)整:
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
檢索或更新緩存中的項
有時候,你可能希望從緩存中檢索出一個項目,但是當(dāng)該項不存在的時候,你也想存儲一個默認(rèn)值到該項。比如,你希望從緩存中檢索出一個用戶。但是他并不存在,所以你需要從數(shù)據(jù)庫中獲取到他,然后添加到緩存中。你可以使用 Cache::remember
方法來做到這些:
$value = Cache::remember('users', $minutes, function () {
return DB::table('users')->get();
});
如果緩存中沒有檢索到該項,傳遞到 remeber
方法中的閉包將會被執(zhí)行并且其執(zhí)行結(jié)果將會在緩存中進(jìn)行替換。
你也可以合并 remember
和 forever
方法:
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
檢索并刪除
如果你需要檢索一個項目,并在檢索到的同時從緩存中刪除該項,你可以使用 pull
方法。就像 get
方法一樣,如果未檢索到該項,將會返回 null
:
$value = Cache::pull('key');
存儲項目到緩存
你可以使用 Cache
假面的 put
方法來存儲項目到緩存中。當(dāng)你存儲一個項到緩存中時,你需要指定一個該項需要被緩存的分鐘值:
Cache::put('key', 'value', $minutes);
除了傳遞一個數(shù)值作為緩存過期的分鐘值,你也可以通過傳遞一個 PHP DateTime
實例來設(shè)置緩存的失效時間:
$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);
add
方法只會在相應(yīng)的項在緩存中不存在時才會被添加進(jìn)緩存。該方法會在項目被添加到緩存后返回 true
。否則返回 false
:
Cache::add('key', 'value', $minutes);
forever
方法可以用來將項目永久的添加進(jìn)緩存。該值只有手動的使用 forget
方法才能被移除:
Cache::forever('key', 'value');
從緩存中移除項目
你可以使用 Cache
假面的 forget
方法來從緩存中移除某項:
Cache::forget('key');
你可以使用 flush
方法來擦除所有的緩存:
Cache::flush();
擦除緩存并不會根據(jù)前綴來進(jìn)行智能擦除,它會移除所有的緩存。所以如果你的應(yīng)用和其他的應(yīng)用共享緩存,你應(yīng)該謹(jǐn)慎的使用該方法。
緩存標(biāo)簽
注意: 緩存標(biāo)簽并不支持
file
或者database
緩存驅(qū)動。另外,對于將多種標(biāo)簽標(biāo)記為永久存儲的驅(qū)動,性能最好的是能夠提供自動清除過期記錄的驅(qū)動,比如memcached
。
存儲標(biāo)記了的項目到緩存
緩存標(biāo)簽允許你將相關(guān)的項目進(jìn)行關(guān)聯(lián)標(biāo)記。并且允許一次性清除所有給定標(biāo)簽的緩存項。你可以通過有序的標(biāo)簽數(shù)組來訪問被標(biāo)記的緩存項目。比如,讓我們訪問被標(biāo)記的項目并使用 put
方法來設(shè)置緩存值:
Cache::tags(['people', 'artists'])->put('John', $john, $minutes);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);
事實上,你并沒有被限制只使用 put
方法。你可以在標(biāo)簽中使用任意的緩存存儲方法。
訪問被標(biāo)記的緩存項
為了訪問被標(biāo)記了的緩存項,你需要傳遞相應(yīng)的有序列表到 tags
方法:
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
你可以一次性的擦除分配的標(biāo)記或者標(biāo)記列表中的所有項。比如,你可以使用 flush
方法來刪除所有的 people
和 authors
標(biāo)簽和兩者組成的有序列標(biāo)簽里的所有緩存項。所以,Anne
和 John
都會被從緩存中移除:
Cache::tags(['people', 'authors'])->flush();
下面的語句將會作為上面語句的對照,將只會從緩存中刪除 authors
標(biāo)簽的項目,所以 Anne
會被刪除,而 John
被保留:
Cache::tags('authors')->flush();
添加自定義的緩存驅(qū)動
為了在自定義的緩存驅(qū)動中繼承 laravel 的緩存。我們需要使用 Cache
假面的 extend
方法,該方法被用來綁定自定義緩存到底層管理中。通常這些都是在服務(wù)提供者中完成。
比如,注冊一個新的緩存驅(qū)動并命名為 '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()
{
//
}
}
第一個被傳遞到 extend
方法中的參數(shù)應(yīng)該是驅(qū)動的名稱。這個名稱應(yīng)該和你的 config/cache.php
配置文件中的 driver
選項一致。而第二個參數(shù)是一個閉包,該閉包應(yīng)該返回一個 Illuminate\Cache\Repository
的實現(xiàn)。在閉包中將會被傳遞一個 $app
實例,這個實例是 laravel 中的服務(wù)容器的實例。
Cache::extend
方法的調(diào)用應(yīng)該在 App\Providers\AppServiceProvider
的 boot
方法中完成。或者你可以創(chuàng)建自己的服務(wù)提供者來存儲這個擴(kuò)展。但是不要忘記在 config/app.php
文件中進(jìn)行注冊。
為了創(chuàng)建我們自己的緩存驅(qū)動,我們首先需要實現(xiàn) Illuminate\Constracts\Cache\Store
契約的接口。所以,我們的 MongoDB 緩存實現(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 連接來實現(xiàn)這些方法。一旦我們的實現(xiàn)完成,我們就可以完成自己的緩存驅(qū)動的注冊:
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
然后在 config/cache.php
配置文件中更新驅(qū)動為的名稱 driver
為你的擴(kuò)展的名稱。
如果你在為自定義的緩存文件應(yīng)該存放在哪里而疑惑,你可以考慮將其發(fā)布到 Packagist!或者,你可以在 app
目錄中創(chuàng)建一個 Extensions
命名空間。事實上,你應(yīng)該謹(jǐn)記,laravel 并不死板的限制你的目錄結(jié)構(gòu),你應(yīng)該可以根據(jù)自己的習(xí)慣自由的管理你的應(yīng)用目錄結(jié)構(gòu)。
事件
如果你想在任何緩存被操作時執(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',
],
];