Skip to main content

缓存

数据缓存

$data = $cache->getOrSet($key, function () {
return $this->calculateSomething();
});

如果匿名函数需要作用域外的数据时,可以使用 use 语句把这些数据传递到匿名函数中。 例如:

$user_id = 42;
$data = $cache->getOrSet($key, function () use ($user_id) {
return $this->calculateSomething($user_id);
});

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 作为底层缓存媒介。

缓存 API

所有缓存组件都有同样的基类 yii\caching\Cache ,因此都支持如下 API:

  • get():通过一个指定的键(key)从缓存中取回一项数据。 如果该项数据不存在于缓存中或者已经过期/失效,则返回值 false。

  • set():将一个由键指定的数据项存放到缓存中。

  • add():如果缓存中未找到该键,则将指定数据存放到缓存中。

  • getOrSet():返回由键指定的缓存项,或者执行回调函数,把函数的返回值用键来关联存储到缓存中, 最后返回这个函数的返回值。

  • multiGet():由指定的键获取多个缓存数据项。

  • multiSet():一次存储多个数据项到缓存中,每个数据都由一个键来指明。

  • multiAdd():一次存储多个数据项到缓存中,每个数据都由一个键来指明。 如果某个键已经存在,则略过该数据项不缓存。

  • exists():返回一个值,指明某个键是否存在于缓存中。

  • delete():通过一个键,删除缓存中对应的值。

  • flush():删除缓存中的所有数据。

缓存过期

// 将数据在缓存中保留 45 秒
$cache->set($key, $data, 45);

sleep(50);

$data = $cache->get($key);
if ($data === false) {
// $data 已过期,或者在缓存中找不到
}

文件依赖(作用:当文件发生修改,被设置的缓存将失效)

$dependency = new \yii\caching\FileDependency(['fileName'=>'hw.txt']);
$cache->add('file_key','hellow world!',3000,$dependency);
var_dump($cache->get('file_key));

表达式依赖(作用:当参数值发生改变,被设置的缓存将要失效)

$dependency = new \yii\caching\ExpressionDependency(
['expression'=>'\YII::$app->request->get("name")']
);
$cache->add('expression_key','hello world!',3000,$dependency);
var_dump($cache->get('expression_key'));

DB依赖

$dependency = new \yii\caching\DbDependency(
['sql'=>'select count(*) from yii.order']
);
$cache->add('db_key','hello world!',3000,$dependency);
var_dump($cache->get('db_key'));

片段缓存

/**  
* 过期时间(duration)
* 或许片段缓存中最常用的一个配置选项就是 duration 了。 它指定了内容被缓存的秒数。 以下代码缓存内容最多一小时:
* 该选项未设置,则它将采用默认值 60,这意味着缓存的内容将在 60 秒后过期。
*/
if ($this->beginCache($id, ['duration' => 3600])) {

// ... 在此生成内容 ...

$this->endCache();
}

//第二个参数也可以设置依赖,例如
$dependency = [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT MAX(updated_at) FROM post',
];

//第二个参数中的enabled可以设置是否启用缓存
['enabled' => false]

片段缓存可以被嵌套使用

if ($this->beginCache($id1)) {
// ...在此生成内容...
if ($this->beginCache($id2, $options2)) {
// ...在此生成内容...
$this->endCache();
}
// ...在此生成内容...
$this->endCache();
}

影响:外层片段缓存会 把内层的数据给缓存了。

当外层缓存的数据过期失效了,内层缓存仍然可能提供有效的片段缓存数据。

如果外层片段缓存没有过期而被视为有效, 此时即使内层片段缓存已经失效,它也将继续提供同样的缓存副本。

动态内容

意思是这部分输出的内容不该被缓存,即便是它被包裹在片段缓存中。

以在片段缓存中调用 yii\base\View::renderDynamic() 去插入动态内容, 如下所示:

if ($this->beginCache($id1)) {
// ...在此生成内容...
echo $this->renderDynamic('return Yii::$app->user->identity->name;');
// ...在此生成内容...
$this->endCache();
}

renderDynamic() 方法接受一段 PHP 代码作为参数。 代码的返回值被看作是动态内容。这段代码将在每次请求时都执行, 无论其外层的片段缓存是否被存储。

页面缓存

页面缓存由 yii\filters\PageCache 类提供支持,该类是一个过滤器。 它可以像这样在控制器类中使用:

public function behaviors()
{
return [
[
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 60,
'variations' => [
\Yii::$app->language,
],
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
],
];
}

这个方法的是在控制器中使用,优先其他方法调用。

only 是指对控制器的那些方法生效。duration 设置多少秒过期 。dependency 缓存依赖。

Http缓存

Last-Modified 头使用时间戳标明页面自上次客户端缓存后是否被修改过。

ETag  头 “Entity Tag”(实体标签,简称 ETag)使用一个哈希值表示页面内容。如果页面被修改过, 哈希值也会随之改变。通过对比客户端的哈希值和服务器端生成的哈希值, 浏览器就能判断页面是否被修改过,进而决定是否应该重新传输内容。

public function behaviors(){
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index'],
'lastModified' => function ($action, $params)
return filemtime('hw.txt'); //获取文件的修改时间
},
'etagSeed' => function ($action, $params) {
$fp = fopen('hw.txt','r'); //获取文件句柄
$title = fgets($fp); //读取文件的第一行
fclose($fp); //关闭连接
return $title;
},
],
];
}
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index'],
'lastModified' => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from('post')->max('updated_at');
},
'etagSeed' => function ($action, $params) {
$post = $this->findModel(\Yii::$app->request->get('id'));
return serialize([$post->title, $post->content]);
},
],
];
}

当规则中同时有lastModified,etagSeed。 lastModified 和 etagSeed 都发生改变,http缓存才会失效。