【问题标题】:Yii - Does database dependency caching work across multiple actions?Yii - 数据库依赖缓存是否适用于多个操作?
【发布时间】:2012-11-11 13:48:55
【问题描述】:

以这段代码为例:

public function actionPostOneWay( $postId )
{
    $dependency = new CDbCacheDependency( 'SELECT publish_date FROM posts WHERE id = :post_id;' );
    $dependency->params = array( 'post_id'=>$postId );
    $post = Post::model()->cache( 59, $dependency )->findByPk( $postId );

    // process post one way
}

public function actionPostAnotherWay( $postId )
{
    $dependency = new CDbCacheDependency( 'SELECT publish_date FROM posts WHERE id = :post_id;' );
    $dependency->params = array( 'post_id'=>$postId );
    $post = Post::model()->cache( 59, $dependency )->findByPk( $postId );

    // process post another way
}

那么访问/postOneWay/postAnotherWay 会重用同一个缓存对象,还是会创建自己的缓存对象?

【问题讨论】:

    标签: caching yii


    【解决方案1】:

    我尝试在两个不同的操作中缓存相同的查询,是的,将使用相同的缓存对象。可以看到在应用的配置文件中启用CProfileLogRoute

    查看CActiveRecord类的源代码我说public function findByPk($pk,$condition='',$params=array())方法(和其他查询方法)使用protected function query($criteria,$all=false)。反过来,这最终依赖于 CDbCommand 类中的 private function queryInternal($method,$mode,$params=array()),Yii 在其中使用数据库查询进行缓存。

    可以看到用于存储和恢复查询结果的缓存键定义如下:

    $cacheKey='yii:dbquery'.$this->_connection->connectionString.':'.$this->_connection->username;
    $cacheKey.=':'.$this->getText().':'.serialize(array_merge($this->_paramLog,$params));
    if(($result=$cache->get($cacheKey))!==false)
    {
        Yii::trace('Query result found in cache','system.db.CDbCommand');
        return $result;
    }
    

    此键不考虑缓存依赖实例。 CDbCacheDependency 仅用于判断数据库是否发生了变化,是否需要执行新的查询来更新缓存。多说一点 - 如果您在两个操作中指定不同的 SQL 来创建 CDbCacheDependency,则只有其中一个(首先执行)在缓存期间才有意义,因为 CDbCacheDependency 的实例与查询结果一起被序列化缓存:

    if(isset($cache,$cacheKey))
        $cache->set($cacheKey, $result, $this->_connection->queryCachingDuration, $this->_connection->queryCachingDependency);
    

    可以在CCache 类的public function set($id,$value,$expire=0,$dependency=null) 方法中看到缓存评估依赖项的实例:

    if ($dependency !== null && $this->serializer !== false)
        $dependency->evaluateDependency();
    
    if ($this->serializer === null)
        $value = serialize(array($value,$dependency));
    elseif ($this->serializer !== false)
        $value = call_user_func($this->serializer[0], array($value,$dependency));
    

    【讨论】:

    • 哇!没想到这么详细。谢谢!大部分都是有道理的。我对这一行感到困惑:“如果您指定不同的 SQL 以在两个操作中创建 CDbCacheDependency,则只有其中一个(首先执行)在缓存期间才有意义,因为 CDbCacheDependency 的实例与查询的结果一起被序列化缓存”。你的意思是说依赖实例正在被缓存和重用?
    • 是的,我就是这个意思。依赖实例将与该值一起缓存,并且下次在if(($result=$cache->get($cacheKey))!==false)条件下检索缓存值时,该实例将用于确定执行依赖查询的数据库是否发生了某些变化,并将结果与​​之前评估的结果进行比较(设置缓存值时)。您可以自己测试它,将CProfileLogRoute添加到应用程序配置的log组件,并将db组件的enableProfile标志设置为true
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 2021-01-21
    • 2013-05-12
    • 1970-01-01
    相关资源
    最近更新 更多