缓存是用于提升网站性能的一种即简单又有效的途径。通过存储相对静态的数据至缓存以备所需,我们可以省去生成这些数据的时间。在 Yii 中使用缓存主要包括配置和访问缓存组件 。
内部方法
一、缓存配置:
1、单一缓存组件配置:
Yii缓存可以在不同的级别使用。在最低级别,可用来缓存单个数据(数据缓存)。往上一级,我们缓存一个由视图脚本生成的页面片断(片段缓存)。在最高级别,可存储整个页面以便需要的时候直接从缓存读取。本文说明页面缓存的配置及实现效果;
实现分为2步;
1. 在config文件加入缓存组件.
'cache' => array (
'class' => 'system.caching.CFileCache',
'directoryLevel' => 2,
),
class标识需要使用的缓存媒介,用途比较广的类型基本都有支持:
CMemCache: 使用 PHP memcache 扩展.
CApcCache: 使用 PHP APC 扩展.
CDbCache: 使用一张数据库表来存储缓存数据。
CFileCache: 使用文件来存储缓存数据。 特别适用于大块数据(例如页面)。
当然,yii也可以支持Redis,需要装一个插件:
http://www.yiibase.com/download/view/32.html
本文实例使用的是文件缓存,对于文件缓存,缓存到的位置为protected/runtime/;directoryLevel设置缓存文件的目录深度;如果缓存页面特别多,这个值需要设置大点,否则每个目录下的页面会很多;对于除class其他的选项的配置,可以查看各class类中的一些属性。
2. 在要做缓存的控制器里定义过滤器。
public function filters() {
return array (
array (
'COutputCache + post, list',
'duration' => 3600,
'varyByParam' => array('id','page'),
'dependency' => array(
'class'=>'CDbCacheDependency',
'sql'=>'SELECT MAX(id) FROM me115_book',
)
);
}
COutputCache 是用于处理缓存的类,如果只填’COutputCache’,则控制器里所有action都会通过缓存过滤,定义’COutputCache + post, list’,表示只对以下方法进行缓存:actionPost, actionList.
duration 是缓存的时间,单位是秒,
varyByParam 是指定一系列GET参数名称列表, 使用相应的值去确定缓存内容的版本,即同一个action用于区分是不同页面的的参数,此处我以id和page来区分不同页面。除varyByParam以外,还可以采用其他的条件来区分页面;
varyByExpression 指定缓存内容通过自定义的PHP表达式的结果而变化;
varyByRoute 指定缓存内容基于请求的路由不同而变化 (controller 和 action);
varyBySession 指定是否缓存内容. 因用户session不同而变化;
dependency 指定缓存失效依赖关系:可指定文件或数据库;本文采用的是数据库依赖CDbCacheDependency;
本例指定的是数据库,通过数据表的某个值的变化来确定缓存是否失效。例如,如果在表中新增了一条me115_book记录,即使缓存才过了2分钟(<3600),仍然判断为失效,从而查询数据库,生成整个页面,再次缓存;
检查:
查看当前页面是否缓存,可以dump输出一个当前服务器时间,从而检查当前页面是否已缓存;
优化效果:
优化站点为一个博客站点(me115.com),除了DNS解析转接外,未进行任何优化,优化前的数据为:
微考教程网-PHP开源框架Yii 缓存配置实例
微考教程网-PHP开源框架Yii 缓存配置实例
首字节时间为842ms;
采用页面缓存之后的效果:
微考教程网-PHP开源框架Yii 缓存配置实例
微考教程网-PHP开源框架Yii 缓存配置实例
首字节时间为376ms;html生成的时间大大缩短,后台时间减少了一倍。
当然,通过本图可以看到整个站点的用时还是比较长,主要是在页面组件(css/js/图片)上的下载耗费了不少时间,后续将针对这方面进行前端优化;
2、多缓存组件配置:
详看:http://hudeyong926.iteye.com/blog/1313713
//不管是多缓存配置还是单缓存配置,都需要设置一个默认的cache组件,因为CDbConnection中的schemaCacheID,queryCacheID,CCacheHttpSession 中的cacheID ,CUrlManager 中的cacheID, CStatePersister 中的cacheID都是默认的 ’cache’
‘cache’ => array(
'class' => 'CFileCache',
),
‘ApcCache’=>array(
'class'=>'CApcCache',
),
'Dbcache'=>array(
'class'=>'CDbCache',
),
'FileCache'=>array(
'class'=>'CFileCache',
'cachePath'=> '/Webroot/trackstar/protected/runtime/cache/test',
),
'MemCache'=>array(
'class'=>'CMemCache',
'servers'=>array(
array(
'host'=>'server1',
'port'=>11211,
'weight'=>60,
),
array(
'host'=>'server2',
'port'=>11211,
'weight'=>40,
),
),
),
session cache在开启apc cache时可以用,它将seesion存到apc中比存到文件中要快
‘cache’ => array(
‘class’ => ‘CApcCache’,
),
‘session’ => array(
‘class’ => ‘CCacheHttpSession’, //CCacheHttpSession在system.web包里
),
yii如果要使用session.save_handler=memcache 如果需要扩展自定义的session管理方法 ,仅仅需要继承CHttpSession, 重写openSession,readSession,writeSession, destroySession,gcSession 这五个方法即可
3、数据库缓存配置:
//main.php配置文件中 数据库缓存配置,具体参照CDbConnection
‘schemaCachingDuration’ => 3600, //缓存时间
‘schemaCachingExclude’ => array(), //不需要缓存的表名数组
‘schemaCacheID’ => ‘cache’, //使用的缓存组件
此外,CDbConnection中还有关于数据库查询的缓存配置,不过这里只是一个全局的配置
//查询缓存配置
‘queryCachingDuration’ => 3600,//缓存时间
‘queryCachingDependency’ => null, //缓存依赖
‘queryCachingCount’ => 2, //第一次使用这条sql语句后同样的多少条sql语句需要缓存
‘queryCacheID’ => ‘cache’, //使用的缓存组件
需要配置数据库查询缓存,可以使用使用以下方法:
一、CDbConnection中的cache方法
public CDbConnection cache(integer
duration,CCacheDependency
dependency=NULL, integer
queryCount=1)
duration integer 查询结果保持在缓存中有效的秒数。如果它是0,缓存将被禁用。
dependencyCCacheDependency当查询结果保存到缓存时,使用的依赖。
queryCount integer 在调用此方法后,需要缓存的SQL查询的数目。默认为 1,意味着下一条SQL查询将被缓存。
{return} CDbConnection 返回连接实例本身。
public function cache(
duration,
dependency=null, queryCount=1)
{this->queryCachingDuration=
duration;
this->queryCachingDependency=
dependency;
this->queryCachingCount=
queryCount;return
this;
}
例子:
sql=‘SELECT∗FROMtblpostLIMIT20′;
dependency = new CDbCacheDependency(‘SELECT MAX(update_time) FROM tbl_post’);
rows=Yii::app()−>db−>cache(1000,
dependency)->createCommand($sql)->queryAll();
二、CActiveRecord中的cache方法:
public CActiveRecord cache(integer
duration,CCacheDependency
dependency=NULL, integer
queryCount=1)
duration integer 查询结果可能保持在缓存中有效的秒数。如果这是0,缓存将被禁用。
dependencyCCacheDependency保存查询结果到缓存时使用的依赖关系。
queryCount integer 在调用此方法后,需要缓存的SQL查询的数目。 默认值为 1,这意味着下一个SQL查询将被缓存。
{return} CActiveRecord AR实例本身。
public function cache(
duration,
dependency=null, queryCount=1)
{
//实际上他调用的是CDbConnection中的cache方法this->getDbConnection()->cache(
duration,
dependency,
queryCount);return
this;
}
例子:
dependency=newCDbCacheDependency(‘SELECTMAX(updatetime)FROMtblpost′);
posts = Post::model()->cache(1000, $dependency)->findAll();
关于$queryCount:
启用查询缓存
要使用查询缓存,首先要确保CDbConnection::queryCacheID指向一个可用的缓存组件ID(默认是cache)。
用DAO查询缓存
要使用查询缓存,我们在数据库查询的时候调用CDbConnection::cache()这个方法。例如:
sql=‘SELECT∗FROMtblpostLIMIT20′;
dependency = new CDbCacheDependency(‘SELECT MAX(update_time) FROM tbl_post’);
rows=Yii::app()−>db−>cache(1000,
dependency)->createCommand($sql)->queryAll();
执行以上语句的时候,Yii会首先检查一下缓存是否包含一个该语句的查询结果。检查步骤是以下的三个条件:
●如果缓存包含了SQL语句中的入口索引
●如果入口还没过期(少于保存后的1000秒)
●如果依赖关系没有变化(update_time的最大值是跟查询结果保存到缓存时一致)
如果以上3个条件都满足了,缓存的结果就会直接返回给请求。否则,SQL语句就会被传递到数据库系统去执行,得到的结果会保存到缓存,返回给请求。
用AR查询缓存
我们也可以用AR来查询缓存。我们用一个类似的方法,调用CActiveRecord::cache():
dependency=newCDbCacheDependency(‘SELECTMAX(updatetime)FROMtblpost′);
posts = Post::model()->cache(1000,
dependency)−>findAll();//relationalARquery
posts = Post::model()->cache(1000, $dependency)->with(‘author’)->findAll();
上面的cache()方法,实际上是CDbConnection::cache()的快捷方式。在内部,当执行AR的查询语句是,Yii会尝试我们之前讲述过的查询缓存。
缓存的多种查询
默认情况下,我们每次调用cache()(不管是CDbConnection 还是 CActiveRecord),都会标记下次要缓存的SQL,其他任何的SQL查询都不会被缓存,除非我们再次调用cache(),例如:
sql=‘SELECT∗FROMtblpostLIMIT20′;
dependency = new CDbCacheDependency(‘SELECT MAX(update_time) FROM tbl post’);
rows=Yii::app()−>db−>cache(1000,
dependency)->createCommand(
sql)−>queryAll();//querycachingwillNOTbeused
rows = Yii::app()->db->createCommand(
sql)−>queryAll();通过传递另一个参数
queryCount到cache()的方法中,我们可以强制多次查询缓存。下面的例子中,通过调用call(),我们指定这个换成必须用于接下来的2次
// …
rows=Yii::app()−>db−>cache(1000,
dependency, 2)->createCommand(
sql)−>queryAll();//querycachingWILLbeused
rows = Yii::app()->db->createCommand($sql)->queryAll();
如你所知,当我们执行关联AR查询时,可能是执行多句的SQL。例如,Post与Coment之间的关系是HAS_MANY,以下的SQL语句是数据库中真正执行的。
it first selects the posts limited by 20;
it then selects the comments for the previously selected posts.
$posts = Post::model()->with(‘comments’)->findAll(array(
‘limit’=>20,
));
如果我们用下面的语句查询缓存,只有第一句会被缓存:
posts=Post::model()−>cache(1000,
dependency)->with(‘comments’)->findAll(array(
‘limit’=>20,
));
如果要缓存两个,我们要提供额外的参数来指明接下来我们要缓存几句:
posts=Post::model()−>cache(1000,
dependency, 2)->with(‘comments’)->findAll(array(
‘limit’=>20,
));
限制
如果查询结果中包含资源句柄,查询访问就不能用了。例如,我们在某些数据库系统中使用BLOB作为字段类型,查询结果会返回一个资源句柄给这个字段。
有些缓存器会有大小限制。例如mencache限制每个入口大小为1M,所以,当一个查询结果大于该大小时,会缓存失败。
二、缓存的运用
提示 : 因为所有这些缓存组件都从同一个基础类 CCache 扩展而来,不需要修改使用缓存的代码即可在不同的缓存组
件之间切换。
缓存可以在不同的级别使用。在最低级别,我们使用缓存来存储单个数据,比如一个变量,我们把它叫做 数据缓存 。
往上一级,我们缓存一个由视图脚本生成的页面片断。在最高级别,我们存储整个页面以便需要的时候直接从缓存读
取。
接下来我们将阐述如何在这些级别上使用缓存。
注意 : 按定义来讲 , 缓存是一个不稳定的存储媒介 , 它不保证缓存一定存在 —— 不管该缓存是否过期 。 所以 , 不要使用
缓存进行持久存储(比如,不要使用缓存来存储 SESSION 数据 ) 。
一、数据缓存
数据缓存也就是在缓存中存储一些 PHP 变量 , 过一会再取出来 。 缓存基础类 CCache 提供了两个最常用的方法 : set()
和 get() 。
要在缓存中存储变量
value,我们选择一个唯一ID并调用set()来存储它:Yii::app()−>cache−>set(
id,
value);被缓存的数据会一直保留在缓存中,直到因一些缓存策略而被删除(比如缓存空间满了,删除最旧的数据)。要改变这一行为,我们还可以在调用set()时加一个过期参数,这样数据过一段时间就会自动从缓存中清除。//在缓存中保留该值最多30秒Yii::app()−>cache−>set(
id, $value, 30);
当我们稍后需要访问该变量时 ( 不管是不是同一 Web 请求 ) , 我们调用 get() ( 传入 ID ) 来从缓存中获取它 。 如果返
回值为 false ,说明该缓存不可用,需要我们重新生成它。
value=Yii::app()−>cache−>get(
id);
if(value===false)
{
// 因为在缓存中没找到,重新生成value
// 再缓存一下以备下次使用
// Yii::app()->cache->set(
id,
value);
}
为一个要缓存的变量选择 ID 时,确保该 ID 在应用中是唯一的。不必保证 ID 在跨应用的情况下保证唯一,因为缓
存组件有足够的智能来区分不同应用的缓存 ID 。
要从缓存中删除一个缓存值 , 调用 delete() ; 要清空所有缓存 , 调用 flush() 。 调用 flush() 时要非常小心 , 因为它会把
其它应用的缓存也清空。
提示 : 因为 CCache 实现了 ArrayAccess 接口,可以像数组一样使用缓存组件。例如:
cache=Yii::app()−>cache;
cache['var1']=
value1;//相当于:
cache->set('var1',
value1);
value2=
cache[‘var2′];//相当于:
value2=
cache−>get(‘var2′);缓存依赖除了过期设置,缓存数据还会因某些依赖条件发生改变而失效。如果我们缓存了某文件的内容,而该文件后来又被更新了,我们应该让缓存中的拷贝失效,从文件中读取最新内容(而不是从缓存)。我们把一个依赖关系表现为一个CCacheDependency或它的子类的实例,调用set()的时候把依赖实例和要缓存的数据一起传入。//缓存将在30秒后过期//也可能因依赖的文件有更新而更快失效Yii::app()−>cache−>set(
id,
value,30,newCFileCacheDependency(‘FileName′));如果我们现在调用get()从缓存中获取
value ,缓存组件将检查依赖条件。如果有变,我们会得到 false 值 —— 数据
需要重新生成。
下面是可用的缓存依赖的简要说明:
CFileCacheDependency: 该依赖因文件的最近修改时间发生改变而改变。
CDirectoryCacheDependency: 该依赖因目录(或其子目录)下的任何文件发生改变而改变。
CDbCacheDependency: 该依赖因指定的 SQL 语句的查询结果发生改变而改变。
CGlobalStateCacheDependency: 该依赖因指定的全局状态值发生改变而改变。全局状态是应用中跨请求、跨 SESSION
的持久变量,它由 CApplication::setGlobalState() 来定义。
CChainedCacheDependency: 该依赖因依赖链中的任何一环发生改变而改变。
二、片段缓存 (Fragment Caching)
片段缓存指缓存网页某片段。例如,如果一个页面在表中显示每年的销售摘要,我们可以存储此表在缓存中,减少每
次请求需要重新产生的时间。
要使用片段缓存,在控制器视图脚本中调用 CController::beginCache() 和 CController::endCache() 。这两种方法开始和
结束包括的页面内容将被缓存。类似 data caching ,我们需要一个编号,识别被缓存的片段。
… 别的 HTML 内容 …