学习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]); } }
相关文章
- 在listView中多个listItem布局时,convertView缓存及使用
- CPU缓存刷新的误解
- Win7如何重建桌面图标缓存
- 使用redis和fastjson做应用和mysql之间的缓存
- 第二百九十五节,python操作redis缓存-字符串类型
- 缓存与内存的区别
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
- 作为前端应当了解的Web缓存知识
- SAP ABAP OData gateway缓存表的存储逻辑 - cache table logic
- 设置google浏览器不缓存JS
- 学习Spring Boot:(二十五)使用 Redis 实现数据缓存
- Vue学习之--------编程式路由导航、缓存路由组件、新的钩子函数(4)(2022/9/5)
- AMD CPU 缓存
- 龙芯软件开发(17)-- 初始化龙芯2E缓存
- Hibernate缓存
- Redis进阶学习09---缓存同步
- Redis进阶学习07--分布式缓存--下
- Redis进阶学习02---Redis替代Session和Redis缓存
- 并发编程 — 缓存一致性问题