zl程序教程

您现在的位置是:首页 >  后端

当前栏目

学习yii2.0——数据缓存、片段缓存、页面缓存、http缓存

缓存学习数据HTTP 页面 片段
2023-09-14 08:56:53 时间

  声明:本文内容来自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]);
	}
}