2012-10-20 66 views
1

我試圖緩存使用Yii框架1.1.12從數據庫中檢索到的一些結果。這是我在做什麼簡而言之:爲什麼CDbCacheDependency的查詢被執行兩次?

public static function getCategories() 
{ 
    if (self::$_categories !== null) 
     return self::$_categories; 

    print "Getting categories...";  
    self::$_categories = Yii::app()->cache->get("categoriesList"); 
    if (self::$_categories === false) 
    { 
     $sql = "SELECT id, parent_id, name FROM {{category}} WHERE id > 0 AND is_deleted = 0"; 
     $categoriesList = Yii::app()->db->createCommand($sql)->queryAll(); 

     // Doing some work with $categoriesList and obtaining self::$_categories as the result 
     // ... 

     $dependency = new CDbCacheDependency("SELECT MAX(update_time) FROM {{category}}"); 
     Yii::app()->cache->set("categoriesList", self::$_categories, 3600, $dependency); 
    } 

    return self::$_categories; 
} 

使用分析工具,我可以看到一切正常。在第一次兩個查詢被執行(每個查詢一次):

SELECT MAX(update_time) FROM arrenda_category 
SELECT id, parent_id, name FROM arrenda_category WHERE id > 0 AND is_deleted = 0 

在進一步要求只有第一個被執行。

問題是,當我在arrenda_category表增加update_time最大值(甚至沒有用我自己編輯的腳本 - 直接從MySQL命令行)和刷新頁面的SELECT MAX(update_time) FROM arrenda_category查詢計數等於2.進一步刷新只給再次執行一次。有趣的是,如果我清除緩存,我也有一個執行SELECT MAX(...) ...查詢。

所以我不明白爲什麼查詢緩存依賴類會在條件發生變化時執行兩次。我的代碼或其他任何東西有問題嗎?

P.S.我確信SELECT MAX(update_time) FROM arrenda_category只能在上述功能中執行。我還看到,每頁請求已達到print "Getting categories..."一行。

回答

3

是的。預計。

說明

假設數據已經在緩存中。當您調用函數getCategories() 時,行Yii::app()->cache->get("categoriesList")將執行相關性查詢以檢查數據是否已更改。由於它沒有改變,查詢只執行一次。

現在你從外部改變update_time值(或使用您的應用程序的一些其他代碼),並調用getCategories()再次,

  1. Yii::app()->cache->get("categoriesList")執行扶養查詢,以檢查是否在緩存中的數據已驗證。報告認爲,數據是無效的,返回false
  2. 那麼查詢SELECT id, parent_id, name FROM {{category}} WHERE id > 0 AND is_deleted = 0執行從數據庫
  3. Yii::app()->cache->set("categoriesList", self::$_categories, 3600, $dependency);AGAIN取得更新數據執行扶養查詢SELECT MAX(update_time) FROM {{category}}以獲得最新的MAX(update_time),其結果一起存儲與數據。這就是爲什麼查詢被執行兩次。

所以問題是,每次你set()一個值緩存,扶養值必須與它一起,因爲它需要爲後續get()查詢檢查依賴性是否改變存儲的時間。

PS: 如果你想要更多的澄清,請檢查您的cache應用程序組件的set()功能的源代碼,它調用CDbCacheDependancy類的evaluateDependency()功能,依次調用這會導致扶養查詢的執行generateDependentData()

+1

謝謝你的明確解釋。然而,有一點奇怪的是,當我使用Yii :: app() - > db-> cache($ duration,$ dependency) - > createCommand($ sql)時,一次執行條件查詢的機會不會被預見到。 - > queryAll();'。嘗試獲取緩存值時,可能會以某種方式更新CDbCacheDependency的'update_time'的新值。無論如何,你是對的 - 唯一的辦法就是看資料來找到這樣一個機會。 – Ezze