資料快取
資料快取即儲存一些 PHP 變數到快取中,以後再從快取中取出來。出於此目的,快取元件的基礎類別 CCache 提供了兩個最常用的方法: set() 和 get()。
要在快取中儲存一個變數 $value
,我們選擇一個唯一 ID 並調用 set() 儲存它:
Yii::app()->cache->set($id, $value);
快取的資料將一直留在快取中,除非它由於某些快取策略(例如快取空間已滿,舊的資料被刪除)而被清除。 要改變這種行為,我們可以在調用 set() 的同時提供一個過期參數,這樣在設定的時間段之後,快取資料將被清除:
// 值 $value 在快取中最多保留 30 秒 Yii::app()->cache->set($id, $value, 30);
稍後當我們需要存取此變數時(在同一個或不同的 Web 請求中),就可以通過 ID 調用 get() 從快取中將其取回。 如果返回的是 false,表示此值在快取中不可用,我們應該重新產生它。
$value=Yii::app()->cache->get($id); if($value===false) { // 因為在快取中沒找到 $value ,重新產生它 , // 並將它存入快取以備以後使用: // Yii::app()->cache->set($id,$value); }
為要存入快取的變數選擇 ID 時,要確保此 ID 對應用程式中所有其他存入快取的變數是唯一的。 而在不同的應用程式之間,這個 ID 不需要是唯一的。快取元件具有足夠的智慧區分不同應用程式中的 ID。
一些快取儲存裝置,例如 MemCache, APC, 支援以批次模式取得多個快取值。這可以減少取得快取資料時帶來的開銷。Yii 提供了一個名為 mget() 的方法來完成此功能。如果底層快取儲存裝置不支援此功能,mget() 依然可以模擬實現它。
要從快取中清除一個快取值,調用 delete(); 要清除快取中的所有資料,調用 flush()。 當調用 flush() 時一定要小心,因為它會同時清除其他應用程式中的快取。
提示: 由於 CCache 實現了
ArrayAccess
,快取元件也可以像一個陣列一樣使用。下面是幾個例子:$cache=Yii::app()->cache; $cache['var1']=$value1; // 相當於: $cache->set('var1',$value1); $value2=$cache['var2']; // 相當於: $value2=$cache->get('var2');
快取相依性
除了過期設置,快取資料也可能會因為相依性條件發生變化而失效。例如,如果我們快取了某些文件的內容,而這些文件發生了改變,我們就應該讓快取的資料失效, 並從文件中讀取最新內容而不是從快取中讀取。
我們將一個相依性關係顯示為一個 CCacheDependency 或其子類別的實體。 當調用 set() 時,我們連同要快取的資料將其一同傳入。
// 此值將在 30 秒後失效 // 也可能因相依性的文件發生了變化而更快失效 Yii::app()->cache->set($id, $value, 30, new CFileCacheDependency('FileName'));
現在如果我們通過調用 get() 從快取中取得 $value
,相依性關係將被檢查,如果發生改變,我們將會得到一個 false 值,表示資料需要被重新產生。
下面是可用的快取相依性的簡要說明:
CFileCacheDependency: 如果文件的最後修改時間發生改變,則相依性改變。
CDirectoryCacheDependency: 如果目錄和其子目錄中的文件發生改變,則相依性改變。
CDbCacheDependency: 如果指定 SQL 語句的查詢結果發生改變,則相依性改變。
CGlobalStateCacheDependency: 如果指定的全域狀態發生改變,則相依性改變。全域狀態是應用程式中的一個跨請求、跨會話的變數。它是通過 CApplication::setGlobalState() 定義的。
CChainedCacheDependency: 如果鏈中的任何相依性發生改變,則此相依性改變。
CExpressionDependency: 如果指定的 PHP 表達式的結果發生改變,則相依性改變。
查詢快取
從版本 1.1.7,Yii 開始支援查詢快取。建立在資料快取上,查詢快取儲存資料庫查詢的結果在快取中,藉此省下未來同樣的資料庫查詢要求的時間,直接由快取提供。
提示: 某些資料庫(例如:MySQL)也支援查詢快取的功能。跟 MySQL 相比,Yii 提供更有彈性且更有效率的查詢快取。
啟用查詢快取
要啟用查詢快取,確認 CDbConnection::queryCacheID 指定到一個有效的快取應用程式元件(預設是 cache
)。
一起使用資料存取物件和查詢快取
要使用查詢快取,呼叫 CDbConnection::cache() 方法當我們進行資料庫查詢。如下所示:
$sql = 'SELECT * FROM tbl_post LIMIT 20'; $dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post'); $rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll();
當執行上述述句,Yii 會先檢查快取是否包含有正要執行的 SQL 述句有效的快取結果。藉由下述三個條件驗證:
- 如果快取包含該 SQL 述句索引的一個項目。
- 如果該項目還沒過期(少於 1000 秒,從他被儲存在快取開始)
- 如果相依性還沒被改變(最大的
update_time
值跟查詢結果被儲存在快取時一樣)
如果上述條件都符合,快取結果會被直接從快取中回傳。否則,SQL 述句會被送到資料庫執行,執行結果會被儲存在快取中再回傳。
一起使用 ActiveRecord 和查詢快取
查詢快取可以跟 Active Record 一起使用。為此,我們呼叫一個相似的 CActiveRecord::cache() 方法如下:
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post'); $posts = Post::model()->cache(1000, $dependency)->findAll(); // 關聯式 AR 查詢 $posts = Post::model()->cache(1000, $dependency)->with('author')->findAll();
這裡的 cache()
其實就是 CDbConnection::cache()。從內部觀察,當執行 AR 產生的 SQL 述句,Yii 會嘗試使用我們上述的查詢快取。
快取多個查詢
預設,每次我們呼叫 cache()
方法(不論 CDbConnection 或 CActiveRecord),他會把下個要執行的 SQL 查詢標記快取。其他的 SQL 查詢就不會被快取,除非我們再次呼叫 cache()
。例如,
$sql = 'SELECT * FROM tbl_post LIMIT 20'; $dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post'); $rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll(); // 查詢快取不會被使用 $rows = Yii::app()->db->createCommand($sql)->queryAll();
藉由提供額外的 $queryCount
參數給 cache()
方法,我們可以強迫多個查詢使用查詢快取。下面的例子,當我們呼叫 cache()
,我們指定下兩個查詢也要被快取:
// ... $rows = Yii::app()->db->cache(1000, $dependency, 2)->createCommand($sql)->queryAll(); // 查詢快取會被使用 $rows = Yii::app()->db->createCommand($sql)->queryAll();
如你所知,當進行關聯式 AR 查詢,多個 SQL 查詢是有可能被執行的(藉由檢查 log messages)。例如,如果 Post
和 Comment
的關係是 HAS_MANY
,那麼下列的程式碼會實際上執行了兩個查詢:
- 首先選擇文章,限制數量 20;
- 再來選擇前面所選文章的評論。
$posts = Post::model()->with('comments')->findAll(array( 'limit'=>20, ));
如果我們使用查詢快取如下,那只有第一個查詢會被快取:
$posts = Post::model()->cache(1000, $dependency)->with('comments')->findAll(array( 'limit'=>20, ));
為了快取這兩個查詢,我們需要提供額外的參數,說明有多少個資料庫查詢要快取:
$posts = Post::model()->cache(1000, $dependency, 2)->with('comments')->findAll(array( 'limit'=>20, ));
限制
快取查詢沒辦法運作在包含有資源句柄的結果。例如,當使用 BLOB
欄位類型,某些資料庫會回傳包含有資源句柄的欄位資料。
某些快取裝置有大小限制。例如,memcache 限制每個項目最大的容量為 1MB。因此,如果查詢結果的大小超出這個限制,快取會失敗。