# 服務 —— 緩存
## 1、配置
Laravel為不同的緩存系統提供了統一的API。緩存配置位于`config/cache.php`。在該文件中你可以指定在應用中默認使用哪個緩存驅動。Laravel目前支持流行的緩存后端如[Memcached](http://memcached.org/)和[Redis](http://redis.io/)等。
緩存配置文件還包含其他文檔化的選項,確保仔細閱讀這些選項。默認情況下,Laravel被配置成使用文件緩存,這會將序列化數據和緩存對象存儲到文件系統。對大型應用,建議使用內存緩存如Memcached或APC,你甚至可以為同一驅動配置多個緩存配置。
### 1.1 緩存預備知識
### 1.1.1?數據庫
使用`database`緩存驅動時,你需要設置一張表包含緩存緩存項。下面是該表的`Schema`聲明:
~~~
Schema::create('cache', function($table) {
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});
~~~
### 1.1.2 Memcached
使用Memcached緩存要求安裝了[Memcached PECL 包](http://pecl.php.net/package/memcached),即PHP Memcached擴展。
[Memcached::addServer](http://php.net/manual/en/memcached.addserver.php)默認配置使用TCP/IP協議:
~~~
'memcached' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100
],
],
~~~
你還可以設置`host`?選項為UNIX socket路徑,如果你這樣做,`port`選項應該置為0:
~~~
'memcached' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
~~~
### 1.1.3?Redis
使用Laravel的Redis緩存之前,你需要通過Composer安裝`predis/predis`包(~1.0)。
了解更多關于Redis的配置,查看[Larave的Redis文檔](http://laravelacademy.org/post/228.html)。
## 2、緩存使用
### 2.1 獲取緩存實例
`Illuminate\Contracts\Cache\Factory`和`Illuminate\Contracts\Cache\Repository`[契約](http://laravelacademy.org/post/95.html)提供了訪問Laravel的緩存服務的方法。`Factory`契約提供了所有訪問應用定義的緩存驅動的方法。`Repository`契約通常是應用中`cache`配置文件中指定的默認緩存驅動的一個實現。
然而,你還可以使用`Cache`[門面](http://laravelacademy.org/post/97.html),這也是我們在整個文檔中使用的方式,`Cache`門面提供了簡單方便的方式對底層Laravel緩存契約實現進行訪問。
例如,讓我們在控制器中導入`Cache`門面:
~~~
<?php
namespace App\Http\Controllers;
use Cache;
use Illuminate\Routing\Controller;
class UserController extends Controller{
/**
* 顯示應用所有用戶列表
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}
~~~
### 2.1.1 訪問多個緩存存儲
使用`Cache`門面,你可以使用`store`方法訪問不同的緩存存儲器,傳入`store`方法的鍵就是cache配置文件中`stores`配置數組里列出的相應的存儲器:
~~~
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 10);
~~~
### 2.2 從緩存中獲取數據
`Cache`門面的`get`方法用于從緩存中獲取緩存項,如果緩存項不存在,返回null。如果需要的話你可以傳遞第二個參數到`get`方法指定緩存項不存在時返回的自定義默認值:
~~~
$value = Cache::get('key');
$value = Cache::get('key', 'default');
~~~
你甚至可以傳遞一個閉包作為默認值,如果緩存項不存在的話閉包的結果將會被返回。傳遞閉包允許你可以從數據庫或其它外部服務獲取默認值:
~~~
$value = Cache::get('key', function() {
return DB::table(...)->get();
});
~~~
### 2.2.1 檢查緩存項是否存在
`has`方法用于判斷緩存項是否存在:
~~~
if (Cache::has('key')) {
//
}
~~~
### 2.2.2 數值增加/減少
`increment`和`decrement`方法可用于調整緩存中的整型數值。這兩個方法都可以接收第二個參數來指明緩存項數值增加和減少的數目:
~~~
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
~~~
### 2.2.3 獲取或更新
有時候你可能想要獲取緩存項,但如果請求的緩存項不存在時給它存儲一個默認值。例如,你可能想要從緩存中獲取所有用戶,或者如果它們不存在的話,從數據庫獲取它們并將其添加到緩存中,你可以通過使用`Cache::remember`方法實現:
~~~
$value = Cache::remember('users', $minutes, function() {
return DB::table('users')->get();});
~~~
如果緩存項不存在,傳遞給`remember`方法的閉包被執行并且將結果存放到緩存中。
你還可以聯合`remember`和`forever`方法:
~~~
$value = Cache::rememberForever('users', function() {
return DB::table('users')->get();});
~~~
### 2.2.4 獲取并刪除
如果你需要從緩存中獲取緩存項然后刪除,你可以使用`pull`方法,和`get`方法一樣,如果緩存項不存在的話返回null:
~~~
$value = Cache::pull('key');
~~~
### 2.3 存儲緩存項到緩存
你可以使用`Cache`?門面上的`put`方法在緩存中存儲緩存項。當你在緩存中存儲緩存項的時候,你需要指定數據被緩存的時間(分鐘數):
~~~
Cache::put('key', 'value', $minutes);
~~~
除了傳遞緩存項失效時間,你還可以傳遞一個代表緩存項有效時間的PHP?`Datetime`實例:
~~~
$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);
~~~
`add`方法只會在緩存項不存在的情況下添加緩存項到緩存,如果緩存項被添加到緩存返回`true`,否則,返回`false`:
~~~
Cache::add('key', 'value', $minutes);
~~~
`forever`方法用于持久化存儲緩存項到緩存,這些值必須通過`forget`方法手動從緩存中移除:
~~~
Cache::forever('key', 'value');
~~~
### 2.4 從緩存中移除數據
你可以使用`Cache`門面上的`forget`方法從緩存中移除緩存項:
~~~
Cache::forget('key');
~~~
## 3、添加自定義緩存驅動
要使用自定義驅動擴展Laravel緩存,我們使用`Cache`門面的`extend`方法,該方法用于綁定定義驅動解析器到管理器,通常,這可以在[服務提供者](http://laravelacademy.org/post/91.html)中完成。
例如,要注冊一個新的命名為“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`方法的第一個參數是驅動名稱。該值對應配置文件`config/cache.php`中的`driver`選項。第二個參數是返回`Illuminate\Cache\Repository`實例的閉包。該閉包中被傳入一個`$app`實例,也就是[服務容器](http://laravelacademy.org/post/93.html)的一個實例。
調用`Cache::extend`可以在默認`App\Providers\AppServiceProvider`中的`boot`方法中完成,或者你也可以創建自己的服務提供者來存放該擴展——只是不要忘了在配置文件`config/app.php`中注冊該提供者。
要創建自定義的緩存驅動,首先需要實現`Illuminate\Contracts\Cache\Store`契約,所以,我們的`MongoDB`緩存實現看起來像這樣子:
~~~
<?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`連接實現每一個方法,實現完成后,我們可以完成自定義驅動注冊:
~~~
Cache::extend('mongo', function($app) {
return Cache::repository(new MongoStore);
});
~~~
擴展完成后,只需要更新配置文件`config/cache.php`的`driver`選項為你的擴展名稱。
如果你在擔心將自定義緩存驅動代碼放到哪,考慮將其放到Packgist!或者,你可以在`app`目錄下創建一個`Extensions`命名空間。然而,記住Laravel并沒有一個嚴格的應用目錄結構,你可以基于你的需要自由的組織目錄結構。
## 4、緩存標簽
> 注意:緩存標簽不支持`file`或`database`緩存驅動,此外,在“永久”存儲緩存中使用多個標簽時,`memcached`之類的驅動有著最佳性能,因為它可以自動清除過期的記錄。
### 4.1 存儲打上標簽的緩存項
緩存標簽允許你給相關的緩存項打上同一個標簽,然后可以輸出被分配同一個標簽的所有緩存值。你可以通過傳遞一個有序的標簽名數組來訪問被打上標簽的緩存。例如,讓我們訪問一個被打上標簽的緩存并將其值放到緩存中:
~~~
Cache::tags(['people', 'artists'])->put('John', $john, $minutes);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);
~~~
然而,并不只限于使用`put`方法,你可以在處理標簽時使用任何混存存儲器提供的方法。
### 4.2 訪問打上標簽的緩存項
要獲取被打上標簽的緩存項,傳遞同樣的有序標簽名數組到`tags`方法:
~~~
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
~~~
通過上面的語句你可以輸出所有分配了該標簽或標簽列表的緩存項,例如,下面這個語句將會移除被打上`people`,`authors`標簽的緩存,或者,`Anne`?和?`John`都會從緩存中移除:
~~~
Cache::tags(['people', 'authors'])->flush();
~~~
相比之下,下面這個語句只會移除被打上?`authors`標簽的緩存,所以`John`會被移除,而`Anne`不會:
~~~
Cache::tags('authors')->flush();
~~~
## 5、緩存事件
要在每次緩存操作時執行代碼,你可以監聽緩存觸發的事件,通常,你可以將這些緩存處理器代碼放到`EventServiceProvider`的`boot`方法中:
~~~
/**
* 注冊應用任意其他事件
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events){
parent::boot($events);
$events->listen('cache.hit', function ($key, $value) {
//
});
$events->listen('cache.missed', function ($key) {
//
});
$events->listen('cache.write', function ($key, $value, $minutes) {
//
});
$events->listen('cache.delete', function ($key) {
//
});
}
~~~
- 前言
- 序言
- 序言 ―― 發行版本說明
- 序言 ―― 升級指南
- 序言 ―― 貢獻代碼
- 開始
- 開始 ―― 安裝及配置
- 開始 ―― Laravel Homestead
- 基礎
- 基礎 ―― HTTP路由
- 基礎 ―― HTTP 中間件
- 基礎 ―― HTTP 控制器
- 基礎 ―― HTTP 請求
- 基礎 ―― HTTP 響應
- 基礎 ―― 視圖
- 基礎 ―― Blade模板
- 架構
- 架構 ―― 一次請求的生命周期
- 架構 ―― 應用目錄結構
- 架構 ―― 服務提供者
- 架構 ―― 服務容器
- 架構 ―― 契約
- 架構 ―― 門面
- 數據庫
- 數據庫 ―― 起步
- 數據庫 ―― 查詢構建器
- 數據庫 ―― 遷移
- 數據庫 ―― 填充數據
- Eloquent ORM
- Eloquent ORM ―― 起步
- Eloquent ORM ―― 關聯關系
- Eloquent ORM ―― 集合
- Eloquent ORM ―― 調整器
- Eloquent ORM ―― 序列化
- 服務
- 服務 ―― 用戶認證
- 服務 ―― Artisan 控制臺
- 服務 ―― Laravel Cashier(交易)
- 服務 ―― 緩存
- 服務 ―― 集合
- 服務 ―― Laravel Elixir
- 服務 ―― 加密
- 服務 ―― 錯誤&日志
- 服務 ―― 事件
- 服務 ―― 文件系統/云存儲
- 服務 ―― 哈希
- 服務 ―― 幫助函數
- 服務 ―― 本地化
- 服務 ―― 郵件
- 服務 ―― 包開發
- 服務 ―― 分頁
- 服務 ―― 隊列
- 服務 ―― Redis
- 服務 ―― Session
- 服務 ―― Envoy 任務運行器(SSH任務)
- 服務 ―― 任務調度
- 服務 ―― 測試
- 服務 ―― 驗證