为什么CDbCacheDependency的查询执行了两次?

时间:2012-10-20 19:52:44

标签: php caching yii

我正在尝试使用Yii framework 1.1.12缓存从数据库检索到的一些结果。以下是我正在做的事情:

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

在进一步的请求中,只执行第一个。

问题是当我在update_time表中增加arrenda_category的最大值时(即使不使用我自己的编辑脚本 - 直接从MySQL命令行)并刷新页面{{1} }查询变为等于2.进一步刷新只会再次执行一次。有趣的是,如果我清除缓存,我也会执行一次SELECT MAX(update_time) FROM arrenda_category查询。

所以我不明白为什么在条件改变时执行两次缓存依赖类的查询。我的代码或其他任何东西都有问题吗?

P.S。我确信SELECT MAX(...) ...只能在上述功能中执行。我还看到每页请求都会找到一行SELECT MAX(update_time) FROM arrenda_category

1 个答案:

答案 0 :(得分: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)。这就是为什么查询执行两次。
  4. 所以重点是每次set()缓存一个值时,必须同时存储依赖值,因为后续的get()查询需要它来检查依赖关系是否已更改

    PS: 如果您需要更多说明,请检查set()应用程序组件的cache函数的源代码,它会调用evaluateDependency()类的CDbCacheDependancy函数,该函数将调用generateDependentData() 3}}导致执行依赖查询