## Yii2数据缓存 [TOC] ### 增删改查 在日常开发中最长用的是对缓存数据的增删改查,具体操作如下: ``` $cache = \Yii::$app->cache; $cache->add('keyName',$keyVal); // 新增缓存数据 $cache->delete('keyName'); // 删除缓存数据 $cache->set('keyName',$newVal); // 修改缓存数据 $cache->get('keyName'); // 获取缓存数据 $cache->flush(); //清空缓存 ``` ### 缓存其他配置 #### 缓存有效期 ``` $cache = \Yii::$app->cache $cache->add('keyName',$keyVal,10); // 新增缓存数据10秒有效 $cache->set('keyName',$keyVal,10); // 设置缓存数据10秒有效 ``` ### 缓存依赖关系   Yii提供了5中依赖方法,Yii中的缓存依赖,简单来说就是将缓存和另外一个东西绑定在一起,如果另外一个东西发生变化,那么缓存也将发生变化,缓存的变动是依赖的东西所导致的。   依赖可以是文件、数据库、甚至是一些表达式,功能十分强大。 #### 文件依赖   顾名思义,缓存除了可以设置有效期可能需要依赖文件,假如我们传入的文件在存储缓存时发生了改变即文件最后修改的时间戳发生了改变,那么将导致缓存失效。 ``` $cache = Yii::$app->cache; // 文件依赖 $dependency = new \yii\caching\FileDependency(['fileName' => 'test.txt']); // $cache->add('file_key','hello world!',100,$dependency); var_dump($cache->get('file_key')); ``` > 上述文件依赖配置中所依赖的文件名是`test.txt` ,我们需要创建一个文件名为`test.txt`在项目根目录下。在修改文件前先运行新增缓存数据操作,然后修改`test.txt`依赖文件后再访问缓存数据返回`false`。 #### 表达式依赖   通过接收地址栏的参数进行缓存数据的依赖处理,如下: ``` $cache = Yii::$app->cache; // 表达式依赖 $dependency = new \yii\caching\ExpressionDependency( ['expression' => '\Yii::$app->request->get("name")'] ); // $cache->add('expression_key', 'hello world!', 100, $dependency); var_dump($cache->get('expression_key')); ``` > 上述**表达式依赖**假如我们在新增缓存数据时候访问的地址传递参数`name`值为`hello`,那么我们在下次访问的时候也需要使用`&name=hello`的方式传递表达式依赖进行缓存的读取,或者过期时间到了没有再次写入数据到缓存,都将返回`false`。 #### 数据库依赖   使用对数据库数据的依赖,我们可以很方便的定义一个sql进行数据库的查询,如果数据库查询条件和上次不符,那么缓存将失败。 ``` $cache = Yii::$app->cache; // DB依赖 $dependency = new \yii\caching\DbDependency( ['sql' => 'SELECT COUNT(*) FROM user'] ); // $cache->add('db_key', 'hello world!', 100, $dependency); var_dump($cache->get('db_key')); ``` > 假如我们当前的项目连接的库下有一个`user`表,那么我们统计表内总共的数据条数,在100秒的缓存有效期内如果数据总量进行了修改,那么缓存将失效,将返回`false`。 #### 链式依赖   链式依赖指我们可以把多个依赖关系传递给一个依赖,任何一个发生变化都会使缓存失效。 ```php $cache = Yii::$app->cache; //表达式依赖 $dp1 = new \yii\caching\ExpressionDependency([ 'expression' => 'count(\Yii::$app->authManager->getPermissionsByUser(Yii::$app->user->id))' ]); // DB依赖 $dp2 = new \yii\caching\DbDependency( ['sql' => 'SELECT COUNT(*) FROM user'] ); $cache->set($key, $value, 0, new \yii\caching\ChainedDependencyChainedDependency([ 'dependencies' => [$dp, $dp2] ])); ``` > 上面的两个依赖关系中只要有一个依赖参数发生变化,缓存数据将失效返回`fasle`。 ### 片段缓存   片段缓存指的是缓存页面内容中的某个片段。我们可以缓存一段页面在我们想存储的介质中,而不用实时的去查询数据库获取数据。 ```php <?php // 缓存时间 // $duration = 50; // 缓存依赖(以文件依赖为例,类似与上面的数据依赖) $dependency = [ 'class' => 'yii\caching\FileDependency', 'fileName' => 'test.txt' ]; // 缓存开关 false 为不开启片段缓存 $enabled = false; ?> <?php if ($this->beginCache('cacheKey', ['duration' => $duration,'dependency' => $dependency, 'enabled' => $enabled])) { ?> <div id="cache_div"> <p>数据被缓存1113322332</p> </div> <?php $this->endCache(); } ?> <div id="no_cache_div"> <p>数据不被缓存222</p> </div> ``` > 我们使用视图中的`beginCache()`和`endCache()`进行缓存片段的操作,同时也可以传递一些参数进行更多的定制操作。 #### 片段缓存的嵌套使用 ``` <?php if ($this->beginCache('cacheKey', ['duration' => 20])) { ?> <div id="cache_div"> <p>数据被缓存</p> <?php if ($this->beginCache('cacheInnerKey', ['duration' => 10])) { ?> <div id="inner_cache_div"> <p>嵌套缓存,被缓存</p> </div> <?php $this->endCache(); } ?> </div> <?php $this->endCache(); } ?> ``` > 如上嵌套缓存代码,在使用的时候需要主要防止内层的缓存时间需要大于外层的嵌套缓存,因为如果外层的缓存时间没有到期而内层的缓存到期了也不会重新去加载内层数据,因为外层数据被缓存。 ### 页面缓存   页面缓存指的是在服务器端缓存整个页面的内容。随后当同一个页面 被请求时,内容将从缓存中取出,而不是重新生成。   页面缓存由 `yii\filters\PageCache` 类提供支持,该类是一个 过滤器。它可以像这样在控制器类中使用: ``` public function behaviors() { return [ 'pageCache' => [ 'class' => 'yii\filters\PageCache', 'only' => ['index'], // 仅缓存index方法 'duration' => 60, // 页面缓存60秒 'variations' => [ \Yii::$app->language, ], 'dependency' => [ // 缓存依赖 'class' => 'yii\caching\DbDependency', 'sql' => 'SELECT COUNT(*) FROM user', ], ], ]; } ``` 页面缓存和[片段缓存](http://www.yiichina.com/doc/guide/2.0/caching-fragment)极其相似。它们都支持 `duration`,`dependencies`, `variations` 和 `enabled` 配置选项。它们的主要区别是页面缓存是由[过滤器](http://www.yiichina.com/doc/guide/2.0/structure-filters)实现, 而片段缓存则是一个[小部件](http://www.yiichina.com/doc/guide/2.0/structure-widgets)。 ### HTTP缓存   通过配置 `yii\filters\HttpCache` 过滤器,控制器操作渲染的内容就能缓存在客户端。`yii\filters\HttpCache` 过滤器仅对 `GET` 和 `HEAD` 请求生效,它能为这些请求设置三种与缓存有关的 HTTP 头。 * yii\filters\HttpCache::lastModified * yii\filters\HttpCache::etagSeed * yii\filters\HttpCache::cacheControlHeader ``` public function behaviors() { return [ [ 'class' => HttpCache::className(), 'only' => ['view'], '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]); }, ] ]; } ``` 具体请[参见官方文档](http://www.yiichina.com/doc/guide/2.0/caching-http)。