学习yii2.0——数据缓存、片段缓存、页面缓存、http缓存
声明:本文内容来自https://www.yiichina.com/doc/guide/2.0/caching-overview
配置缓存
yii框架的配置文件config/web.php中,在$config数组中的component中,有一项就是cache。yii框架默认提供的是文件缓存,如下:
$config = [
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
]
]
]
在yii框架中,缓存也是一个组件,那么使用组件的方式和使用request和session组件的方式相同,直接使用Yii::$app->cache即可。
缓存 API
所有缓存组件都有同样的基类 yii\caching\Cache ,因此都支持如下 API:
-
- get():通过一个指定的键(key)从缓存中取回一项数据。 如果该项数据不存在于缓存中或者已经过期/失效,则返回值 false。
- set():将一个由键指定的数据项存放到缓存中。
- add():如果缓存中未找到该键,则将指定数据存放到缓存中。
- getOrSet():返回由键指定的缓存项,或者执行回调函数,把函数的返回值用键来关联存储到缓存中, 最后返回这个函数的返回值。
- multiGet():由指定的键获取多个缓存数据项。
- multiSet():一次存储多个数据项到缓存中,每个数据都由一个键来指明。
- multiAdd():一次存储多个数据项到缓存中,每个数据都由一个键来指明。 如果某个键已经存在,则略过该数据项不缓存。
- exists():返回一个值,指明某个键是否存在于缓存中。
- delete():通过一个键,删除缓存中对应的值。
- flush():删除缓存中的所有数据。
文件缓存
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
class HelloController extends Controller {
public function actionIndex()
{
$cache = Yii::$app->cache;
$cache->set("one", "hello world",5); //5s过期
$cache->add("two", "hello yii"); //永久有效
// $cache->delete("two");
//如果判断是否获取到值,请使用===
if ($cache->get("one")===false) {
echo "not store or timeout";
} else {
echo $cache->get("one");
}
$cache->flush();
}
}
使用memcache缓存
在配置的时候,修改配置如下:
'components' => [
'cache' => [
'class' => 'yii\caching\MemCache',
'servers' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100,
],
[
'host' => '127.0.0.1',
'port' => 11212,
'weight' => 50,
],
],
],
],
缓存依赖
yii框架提供了缓存依赖的概念,除了超时设置,缓存数据还可能受到缓存依赖的影响而失效,比如以下常用的依赖:
- yii\caching\DbDependency:如果指定 SQL 语句的查询结果发生了变化,则依赖改变。
- yii\caching\ExpressionDependency:如果指定的 PHP 表达式执行结果发生变化,则依赖改变。
- yii\caching\FileDependency:如果文件的最后修改时间发生变化,则依赖改变。
文件依赖
在保存cache的时候,指定了文件依赖之后,那么cache项失效会发生在下面的情况:
1、cache超时了,所以被删除了
2、cache未超时,但是呢,当时设置文件依赖的那个文件发生了改变,那么cache也会被删除。
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
class HelloController extends Controller {
//设置缓存
public function actionIndex()
{
$cache = Yii::$app->cache;
if ($cache->get("one")===false) {
//文件路径的基地址是web/目录(入口文件的目录)
$fileDependency = new \yii\caching\FileDependency(["fileName" => "demo.txt"]);
//设置缓存的时候,加上过期时间和文件依赖
$cache->add("one", "hello world", 60, $fileDependency);
}
echo $cache->get("one");
}
}
第一次访问hello/setcache的时候,因为cache中没有内容,所以会设置cache,并且设置文件依赖。再次访问hello/getcache的时候,如果cache未过期,或者说demo.txt没有被修改,那么就能获取到cache中one的值为hello world。但是如果在未过期之前,修改了文件内容,那么再次访问cache中的one的时候,就不能获取到其值了。
表达式依赖
表达式依赖和文件依赖很相似:
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
class HelloController extends Controller {
//设置缓存
public function actionIndex()
{
$cache = Yii::$app->cache;
if ($cache->get("one")===false) {
$expressionDependency = new \yii\caching\ExpressionDependency(
//指定expression的值,expression是字符串类型
//如果在访问cache时,发现数组中接受的值发生了改变,那么对应的cache就失效了
["expression" =>'Yii::$app->request->get("id")']
);
//设置缓存的时候,加上过期时间和文件依赖
$cache->add("one", "hello world expressionDependency", 60, $expressionDependency);
}
echo $cache->get("one");
}
}
首次访问hello/index的时候,如果传递的URL中id=1,那么这一次的id会在存cache的时候,被当作表达式依赖。下一次访问cache时,如果id仍然为1,那么就可以获取到cache中的值,但是如果id为2,那么表示依赖变了,那么就不能获取到cache中的值了,因为cache已经过期了。
数据库依赖
在设置cache的时候,会加上数据库依赖(需要一个SQL语句),这个sql语句会执行一次,并将结果保存在DbDependency::data中,之后访问cache时,如果指定 SQL 语句的查询结果发生了变化,则依赖改变,那么cache就会失效了。
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
class HelloController extends Controller {
//设置缓存
public function actionIndex()
{
$cache = Yii::$app->cache;
if ($cache->get("one")===false) {
$cache = Yii::$app->cache;
$dbDependency = new \yii\caching\DbDependency(
//直接写sql语句,yii回去执行sql,将结果与之前的结果进行对比,如果结果不相同,那么cache就会过期
["sql" => "select * from stu" ]
);
//设置缓存的时候,加上过期时间和文件依赖
$cache->add("one", "hello world dbDependency", 60, $dbDependency);
}
echo $cache->get("one");
}
}
片段缓存
1、片段缓存是用在视图文件中的
2、有些页面的数据,在短期内不会改变的,比如说统计数据生成的报表(各种图),这个一般是一段时间统计一次,如果每次请求的时候,就将数据库中的数据取出来进行计算一次,那么这无疑是低效的。那么可以采用片段缓存的做法,将页面中的某些部分缓存起来,下一次请求的时候,这部分缓存起来的数据就从缓存中取,而不用去再计算一次。
<!-- 需要进行缓存的片段,key和视图中的id不需要完全一样-->
<?php if ($this->beginCache("demo",["duration" => 30])){ ?>
<div id="demo">
<?= $time_1 ?>
</div>
<?php $this->endCache();} ?>
<!-- 无需缓存的片段 -->
<?= $time_2 ?>
$this->beginCache($key, $config)方法:
1、如果$key对应的片段缓存不存在的话,或者说已经过期失效了,那么$this->beginCache($key)就会返回true;那么接下来要做的就是进行缓存操作。
2、如果$key对应的片段缓存已经存在,并且没有过期失效,那么$this->beginCache()就返回false;那么就不会显示视图中该部分的内容,直接从cache中读取内容显示。
控制器如下:
<?php
namespace app\controllers;
use yii\web\Controller;
class HelloController extends Controller {
public function actionIndex()
{
$time = date("Y-m-d H:i:s",time());
return $this->renderPartial("index", ["time_1" => $time, "time_2" => $time]);
}
}
访问hello/index,如果没有片段缓存的情况下,视图中显示的两个时间应该是相同的;
但是,第一个时间有片段缓存,那么只有在第一次访问的时候,两个时间是一样的,之后,第一个时间被缓存了,而第二个时间并没有。那么在缓存没有过期的前提下,无论怎么修改time_1的值,都不会生效,因为读取的都是缓存中的time_1。
所以尝试刷新页面(重复请求hello/index),$time在不停改变,time_1和time_2虽然时刻改变,但是视图中,只有time_2在变。
片段缓存中引入缓存依赖
和前面的缓存依赖是一样的原理,用法如下:
<?php
$dbDependency = [
"class" => "yii\caching\DbDependency",
"sql" => "select * from stu"
];
$fileDependency = [
"class" => "yii\caching\FileDependency",
"fileName" => "demo.txt"
];
$expressionDependency = [
"class" => "yii\caching\ExpressionDependency",
"expression" => \Yii::$app->request->get("id")
]
?>
<!-- key和视图中的id不需要完全一样-->
<?php if ($this->beginCache("demo",["duration" => 30, "dependency" => $dbDependency])){ ?>
<div id="demo">
<?= $time_1 ?>
</div>
<?php $this->endCache();} ?>
<!-- 无需缓存的片段 -->
<?= $time_2 ?>
页面缓存
页面缓存其实是和片段缓存对应的,片段缓存只缓存视图中的某一部分,所以叫“片段”缓存,而页面缓存则是缓存整个页面。
需要用到控制器中的一个方法behaviors(),这个方法在控制器中有点特别,因为他是在执行action之前调用的,比如请求HelloController/actionIndex方法,会首先调用behaviors方法,然后在调用actionIndex方法。
所以可以在behaviors方法中来对某些action的响应进行缓存,假设对actionIndex和actionAbout进行了缓存,那么下一次对这两个action的请求,就直接从cache中读数据,而不用再次调用actionIndex或者actionAbout了。
public function behaviors()
{
return [
[
'class' => 'yii\filters\PageCache',
'only' => ['index', 'about'],
'duration' => 60,
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
],
];
}
和片段缓存一样可以使用缓存依赖。
HTTP缓存
http缓存和页面缓存差不多,区别是:
1、页面缓存是在服务器的cache中取出数据,然后返回给客户端。
2、http缓存是在客户端(浏览器)中缓存数据,客户端直接从本地读取数据,而不用服务器再次将相同的数据返回给客户端。
关于http缓存的知识,可以看一下这个权威:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ
注意,yii框架的http缓存只对get和head请求有效。
注意Last-Modified和Etag的功能,首先区分Last-Modified(文件最后一次修改的时间戳),如果发生了改变,那么再看Etag是否发生了改变,如果只是Last-Modified发生了改变,而Etag没有发生变化,那么仍旧返回给客户端一个304(Not Modified)。只有当文件内容发生变化时(Etag发生变化时),才重新返回资源给客户端。
http缓存和页面缓存的做法差不多,具体如下:
<?php
namespace app\controllers;
use yii\web\Controller;
class HelloController extends Controller {
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index', 'about'],
'lastModified' => function() {
return filemtime("demo.txt"); //某个文件最后修改时间
},
'etagSeed' => function ($action, $params) {
return md5(file_get_contents("demo.txt")); //返回校验值
},
],
];
}
public function actionIndex()
{
$time = date("Y-m-d H:i:s",time());
return $this->renderPartial("index", ["time_1" => $time, "time_2" => $time]);
}
public function actionAbout()
{
$time = date("Y-m-d H:i:s",time());
return $this->renderPartial("index", ["time_1" => $time, "time_2" => $time]);
}
}
浙公网安备 33010602011771号