為了那些因為標題點進來的小伙伴,我直接把問題解決方案寫在開頭:
問題描述,
$cache->add($key,'value',1800);
這樣設置了值后,后面無論怎么取這個$key,取出來的結果都是false, 使用$cache->exit ,也顯示不存在
原因:因為我在設置$key的時候,使用的$key = time();經過測試yii2的緩存,是不能使用純數字的鍵,最后使用了$key = 'name'.$key;就好了
數據緩存
數據緩存是指將一些 PHP 變量存儲到緩存中,使用時再從緩存中取回。 它也是更高級緩存特性的基礎,例如查詢緩存和內容緩存。
如下代碼是一個典型的數據緩存使用模式。 其中 $cache
指向緩存組件:
1 // 嘗試從緩存中取回 $data 2 $data = $cache->get($key); 3 4 if ($data === false) { 5 6 // $data 在緩存中沒有找到,則重新計算它的值 7 8 // 將 $data 存放到緩存供下次使用 9 $cache->set($key, $data); 10 } 11 12 // 這兒 $data 可以使用了。 13 從 2.0.11 版本開始, 緩存組件 提供了 getOrSet() 方法來簡化數據的取回、計算和存儲。 下面的代碼邏輯和上一個例子是完全一樣的: 14 15 $data = $cache->getOrSet($key, function () { 16 return $this->calculateSomething(); 17 });
當緩存中有關聯 $key 的數據時,將返回這個緩存的值。 否則就執行匿名函數來計算出將要緩存的數據並返回它。
如果匿名函數需要作用域外的數據時,可以使用 use
語句把這些數據傳遞到匿名函數中。 例如:
$user_id = 42; $data = $cache->getOrSet($key, function () use ($user_id) { return $this->calculateSomething($user_id); });
注意: getOrSet() 方法也支持緩存持續性和緩存依賴。 請看緩存過期 和 緩存依賴 來了解詳細信息。
緩存組件
數據緩存需要緩存組件提供支持,它代表各種緩存存儲器, 例如內存,文件,數據庫。
緩存組件通常注冊為應用程序組件,這樣它們就可以 在全局進行配置與訪問。如下代碼演示了如何配置應用程序組件cache
使用兩個 memcached 服務器:
'components' => [ 'cache' => [ 'class' => 'yii\caching\MemCache', 'servers' => [ [ 'host' => 'server1', 'port' => 11211, 'weight' => 100, ], [ 'host' => 'server2', 'port' => 11211, 'weight' => 50, ], ], ], ],
然后就可以通過 Yii::$app->cache
訪問上面的緩存組件了。
由於所有緩存組件都支持同樣的一系列 API ,並不需要修改使用緩存的業務代碼 就能直接替換為其他底層緩存組件,只需在應用配置中重新配置一下就可以。 例如,你可以將上述配置修改為使用 APC cache:
1 'components' => [ 2 'cache' => [ 3 'class' => 'yii\caching\ApcCache', 4 ], 5 ],
提示: 你可以注冊多個緩存組件,很多依賴緩存的類默認調用 名為
cache
的組件(例如 yii\web\UrlManager)。
支持的緩存存儲器
Yii 支持一系列緩存存儲器,概況如下:
- yii\caching\ApcCache:使用 PHP APC 擴展。 這個選項可以認為是集中式應用程序環境中 (例如:單一服務器,沒有獨立的負載均衡器等)最快的緩存方案。
- yii\caching\DbCache:使用一個數據庫的表存儲緩存數據。要使用這個緩存, 你必須創建一個與 yii\caching\DbCache::$cacheTable 對應的表。
-
為了增強 ArrayCache 的性能,您可以通過將 yii\caching\ArrayCache::$serializer 設置為
false
來禁用已存儲數據的序列化。 - yii\caching\DummyCache:僅作為一個緩存占位符,不實現任何真正的緩存功能。 這個組件的目的是為了簡化那些需要查詢緩存有效性的代碼。例如, 在開發中如果服務器沒有實際的緩存支持,用它配置一個緩存組件。 一個真正的緩存服務啟用后,可以再切換為使用相應的緩存組件。 兩種條件下你都可以使用同樣的代碼
Yii::$app->cache->get($key)
嘗試從緩存中取回數據而不用擔心Yii::$app->cache
可能是null
。 - yii\caching\FileCache:使用標准文件存儲緩存數據。 這個特別適用於緩存大塊數據,例如一個整頁的內容。
- yii\caching\MemCache:使用 PHP memcache 和 memcached 擴展。 這個選項被看作分布式應用環境中(例如:多台服務器,有負載均衡等) 最快的緩存方案。
- yii\redis\Cache:實現了一個基於 Redis 鍵值對存儲器的緩存組件 (需要 redis 2.6.12 及以上版本的支持 )。
- yii\caching\WinCache:使用 PHP WinCache (另可參考)擴展.
- yii\caching\XCache:使用 PHP XCache擴展。
- yii\caching\ZendDataCache:使用 [Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm) 作為底層緩存媒介。
提示: 你可以在同一個應用程序中使用不同的緩存存儲器。一個常見的策略是使用基於內存的緩存存儲器 存儲小而常用的數據(例如:統計數據),使用基於文件或數據庫的緩存存儲器 存儲大而不太常用的數據(例如:網頁內容)。
緩存 API
所有緩存組件都有同樣的基類 yii\caching\Cache ,因此都支持如下 API:
- get():通過一個指定的鍵(key)從緩存中取回一項數據。 如果該項數據不存在於緩存中或者已經過期/失效,則返回值 false。
- set():將一個由鍵指定的數據項存放到緩存中。
- add():如果緩存中未找到該鍵,則將指定數據存放到緩存中。
- getOrSet():返回由鍵指定的緩存項,或者執行回調函數,把函數的返回值用鍵來關聯存儲到緩存中, 最后返回這個函數的返回值。
- multiGet():由指定的鍵獲取多個緩存數據項。
- multiSet():一次存儲多個數據項到緩存中,每個數據都由一個鍵來指明。
- multiAdd():一次存儲多個數據項到緩存中,每個數據都由一個鍵來指明。 如果某個鍵已經存在,則略過該數據項不緩存。
- exists():返回一個值,指明某個鍵是否存在於緩存中。
- delete():通過一個鍵,刪除緩存中對應的值。
- flush():刪除緩存中的所有數據。
注意: 千萬別直接用
false
布爾值當做數據項緩存,因為 get() 方法用false
作為返回值來表名對應的緩存項不存在。 你可以把false
放到一個數組里然后緩存這個數組來避免上述的混淆問題。
有些緩存存儲器如 MemCache,APC 支持以批量模式取回緩存值,這樣可以節省取回緩存數據的開支。 multiGet() 和 multiAdd() API提供對該特性的支持。 如果底層緩存存儲器不支持該特性,Yii 也會模擬實現。
由於 yii\caching\Cache 實現了 PHP ArrayAccess
接口, 緩存組件也可以像數組那樣使用,下面是幾個例子:
$cache['var1'] = $value1; // 等價於: $cache->set('var1', $value1); $value2 = $cache['var2']; // 等價於: $value2 = $cache->get('var2');
緩存鍵
存儲在緩存中的每項數據都通過鍵作唯一識別。 當你在緩存中存儲一項數據時,必須為它指定一個鍵, 稍后從緩存中取回數據時,也需要提供相應的鍵。
你可以使用一個字符串或者任意值作為一個緩存鍵。當鍵不是一個字符串時, 它將會自動被序列化為一個字符串。
定義一個緩存鍵常見的一個策略就是在一個數組中包含所有的決定性因素。 例如,yii\db\Schema 使用如下鍵存儲一個數據表的結構信息。
1 [ 2 __CLASS__, // 結構類名 3 $this->db->dsn, // 數據源名稱 4 $this->db->username, // 數據庫登錄用戶名 5 $name, // 表名 6 ];
如你所見,該鍵包含了可唯一指定一個數據庫表所需的所有必要信息。
注意: 通過 multiSet() 或者 multiAdd() 方法緩存的數據項的鍵,它的類型只能是字符串或整型, 如果你想使用較為復雜的鍵,可以通過 set() 或者 add() 方法來存儲。
當同一個緩存存儲器被用於多個不同的應用時,應該為每個應用指定一個唯一的緩存鍵前綴以避免緩存鍵沖突。 可以通過配置 yii\caching\Cache::$keyPrefix 屬性實現。 例如,在應用配置中可以編寫如下代碼:
1 'components' => [ 2 'cache' => [ 3 'class' => 'yii\caching\ApcCache', 4 'keyPrefix' => 'myapp', // 唯一鍵前綴 5 ], 6 ],
為了確保互通性,此處只能使用字母和數字。
緩存過期
默認情況下,緩存中的數據會永久存留,除非它被某些緩存策略強制移除(例如:緩存空間已滿,最老的數據會被移除)。 要改變此特性,你可以在調用 set() 存儲一項數據時提供一個過期時間參數。 該參數代表這項數據在緩存中可保持有效多少秒。 當你調用 get() 取回數據時, 如果它已經過了超時時間,該方法將返回 false,表明在緩存中找不到這項數據。 例如:
1 // 將數據在緩存中保留 45 秒 2 $cache->set($key, $data, 45); 3 4 sleep(50); 5 6 $data = $cache->get($key); 7 if ($data === false) { 8 // $data 已過期,或者在緩存中找不到 9 }
從 2.0.11 開始,如果想自定義緩存的持續時間,你可以在緩存組件配置中設置 defaultDuration 成員屬性的值。 這樣設置會覆蓋默認的緩存持續時間,且在使用 set() 方法時不必每次都傳遞 $duration
參數。
緩存依賴
除了超時設置,緩存數據還可能受到緩存依賴的影響而失效。 例如,yii\caching\FileDependency 代表對一個文件修改時間的依賴。 這個依賴條件發生變化也就意味着相應的文件已經被修改。 因此,緩存中任何過期的文件內容都應該被置為失效狀態, 對 get() 的調用都應該返回 false。
緩存依賴用 yii\caching\Dependency 的派生類所表示。 當調用 set() 在緩存中存儲一項數據時, 可以同時傳遞一個關聯的緩存依賴對象。例如:
1 // 創建一個對 example.txt 文件修改時間的緩存依賴 2 $dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']); 3 4 // 緩存數據將在30秒后超時 5 // 如果 example.txt 被修改,它也可能被更早地置為失效狀態。 6 $cache->set($key, $data, 30, $dependency); 7 8 // 緩存會檢查數據是否已超時。 9 // 它還會檢查關聯的依賴是否已變化。 10 // 符合任何一個條件時都會返回 false。 11 $data = $cache->get($key);
下面是可用的緩存依賴的概況:
- yii\caching\ChainedDependency:如果依賴鏈上任何一個依賴產生變化,則依賴改變。
- yii\caching\DbDependency:如果指定 SQL 語句的查詢結果發生了變化,則依賴改變。
- yii\caching\ExpressionDependency:如果指定的 PHP 表達式執行結果發生變化,則依賴改變。
- yii\caching\FileDependency:如果文件的最后修改時間發生變化,則依賴改變。
- yii\caching\TagDependency:將緩存的數據項與一個或多個標簽相關聯。 您可以通過調用 yii\caching\TagDependency::invalidate() 來檢查指定標簽的緩存數據項是否有效。
注意: 避免對帶有緩存依賴的緩存項使用 exists() 方法, 因為它不檢測緩存依賴(如果有的話)是否有效,所以調用 get() 可能返回
false
而調用 exists() 卻返回true
。
查詢緩存
查詢緩存是一個建立在數據緩存之上的特殊緩存特性。 它用於緩存數據庫查詢的結果。
查詢緩存需要一個 數據庫連接 和一個有效的 cache
應用組件。 查詢緩存的基本用法如下,假設 $db
是一個 yii\db\Connection 實例:
1 $result = $db->cache(function ($db) { 2 3 // SQL 查詢的結果將從緩存中提供 4 // 如果啟用查詢緩存並且在緩存中找到查詢結果 5 return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne(); 6 7 });
查詢緩存可以用在DAO和ActiveRecord上:
1 $result = Customer::getDb()->cache(function ($db) { 2 return Customer::find()->where(['id' => 1])->one(); 3 });
信息: 有些 DBMS (例如:MySQL) 也支持數據庫服務器端的查詢緩存。 你可以選擇使用任一查詢緩存機制。 上文所述的查詢緩存的好處在於你可以指定更靈活的緩存依賴因此可能更加高效。
自 2.0.14 以后,您可以使用以下快捷方法:
1 (new Query())->cache(7200)->all(); 2 // and 3 User::find()->cache(7200)->all();
配置
查詢緩存通過 yii\db\Connection 有三個全局可配置選項:
- enableQueryCache:是否打開或關閉查詢緩存。 它默認為
true
。 請注意,要有效打開查詢緩存, 您還需要有一個由 queryCache 所指定的有效緩存。 - queryCacheDuration:這表示查詢結果在緩存中保持有效的秒數。 您可以使用 0 來表示查詢結果永久保留在緩存中。 該屬性是在未指定持續時間的情況下調用 yii\db\Connection::cache() 使用的默認值。
- queryCache:緩存應用組件的 ID。默認為
'cache'
。 只有在設置了一個有效的緩存應用組件時,查詢緩存才會有效。
使用
如果您有多個需要利用查詢緩存的 SQL 查詢,則可以使用 yii\db\Connection::cache()。 用法如下,
1 $duration = 60; // 緩存查詢結果 60 秒。 2 $dependency = ...; // 可選的依賴關系 3 4 $result = $db->cache(function ($db) { 5 6 // ... 在這里執行 SQL 查詢 ... 7 8 return $result; 9 10 }, $duration, $dependency);
在匿名函數里的任何一個 SQL 查詢都將使用指定的依賴項緩存指定的持續時間 如果一個 SQL 查詢的結果在緩存中有效,那么這個 SQl 語句將會被跳過而它的查詢結果會直接從緩存中讀取。 如果你沒有指明 $duration
參數, 那么使用 queryCacheDuration 屬性。
有時在cache()
里,你可能不想緩存某些特殊的查詢, 這時你可以用yii\db\Connection::noCache()。
1 $result = $db->cache(function ($db) { 2 3 // 使用查詢緩存的 SQL 查詢 4 5 $db->noCache(function ($db) { 6 7 // 不使用查詢緩存的 SQL 查詢 8 9 }); 10 11 // ... 12 13 return $result; 14 });
如果您只想為單個查詢使用查詢緩存,則可以在構建命令時調用 yii\db\Command::cache()。 例如,
// 使用查詢緩存並將查詢緩存持續時間設置為 60 秒 $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();
您還可以使用 yii\db\Command::noCache() 禁用單個命令的查詢緩存。例如,
1 $result = $db->cache(function ($db) { 2 3 // 使用查詢緩存的 SQL 查詢 4 5 // 對此命令不使用查詢緩存 6 $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne(); 7 8 // ... 9 10 return $result; 11 });
限制條件
當查詢結果中含有資源句柄時,查詢緩存無法使用。 例如,在有些 DBMS 中使用了 BLOB
列的時候, 緩存結果會為該數據列返回一個資源句柄。
有些緩存存儲器有大小限制。例如,memcache 限制每條數據最大為 1MB。 因此,如果查詢結果的大小超出了該限制, 則會導致緩存失敗。
緩存沖刷 ¶
當你想讓所有的緩存數據失效時,可以調用 yii\caching\Cache::flush()。
沖刷緩存數據,你還可以從控制台調用 yii cache/flush
。
yii cache
:列出應用中可用的緩存組件yii cache/flush cache1 cache2
:刷新緩存組件cache1
,cache2
(可以傳遞多個用空格分開的緩存組件)yii cache/flush-all
:刷新應用中所有的緩存組件yii cache/flush-schema db
:清除給定連接組件的數據庫表結構緩存