Drupal专业开发指南 第15章 缓存

老葛的Drupal培训班 Think in Drupal

在为动态网站构建页面时,需要对数据库进行大量的查询操作,以获取相关信息比如保存的内容、站点设置、当前用户等等。将这些耗费资源的操作的结果保存起来以备后用,这是从应用层提升站点性能的最佳途径之一。这里被保存的不仅仅是数据库调用,在PHP中对取回的信息所作的处理也被保存了起来。Drupal内置的缓存API对大部分核心数据进行了自动缓存,并为Drupal开发者提供了一组工具以进行量身定做。例如,memcache模块(http://drupal.org/project/memcache)就是一个基于内存缓存的例子,它就使用了Drupal的缓存API。
 
注意 本章所讲的是Drupal应用层中的缓存。其它层的缓存,比如数据库的内部缓存(例如,MySQL的查询缓存),也能极大地提升性能。在第22章中提到了这些方面。
 

Drupal版本:

Drupal专业开发指南 第15章 什么时候使用缓存

老葛的Drupal培训班 Think in Drupal

有一点需要记住,那就是使用缓存时要进行权衡。对大量的数据进行缓存,可对性能有很大提升,这是不假,但这是有前提的,前提就是被缓存的数据在接下来能被重复使用。这就是为什么Drupal内置的页面缓存仅用于匿名用户----注册用户通常需要的是页面的定制版本,这样缓存的效果就不太明显。对小量的数据进行缓存(比如今天的流行文章列表),尽管对你网站性能的提升不是很大,但是也会有所改善。
     另外要讲的是,对不经常变动的数据使用缓存效果会更好。比如,对于每周热门故事列表,就比较适用。如果对于一个繁忙的论坛,缓存最新的5条评论,那么效果就不太明显,因为被缓存的数据很快就会过期,还没有多少用户使用到它呢,它就需要更新了。在最坏的情况下,一个坏的缓存策略(比如,对变动过于频繁的数据进行缓存)可能会增加网站的负担,而不是提升性能。
 

Drupal版本:

Drupal专业开发指南 第15章 缓存是如何工作的

     模块常常需要进行昂贵的数据查询或者调用远程web服务。对于这些耗费资源的操作,不需要每次都重复进行一次,模块可以将它们的数据缓存到Drupal中为缓存保留的数据库表中,或者模块也可以创建一个新的数据库表,并将缓存数据存储在那里。当下次用到这些数据时,通过一个简单的查询就可以快速的将其取回。你将在本章的后面看到,Drupal的缓存后端是可插拔的,所以尽管这里所指的是数据库表,实际的后端也可以采用其它的存储,比如直接使用文件或者一个基于内存的缓存。

     在你的模块中,你可以存储缓存信息的默认数据库表是cache。当缓存信息的数据量不大时,最好使用该表。如果你想为每个节点、菜单、用户缓存信息,那么你将需要为你的模块创建一个它自己专有的缓存表。这样就可以减小Drupal的cache表中的记录数量,以及减少写入冲突,从而提升性能。当要为你的模块创建一个新的缓存表时,该表的数据结构一定要与默认的cache表的结构完全相同,这里只有表的名字不同。为了保持一致性,最好在表的名字前面加上前缀cache_。让我们看一下cache表的数据库结构;参看表格15-1.
 
注意 当为你的模块创建一个新的缓存表时,该表的数据结构一定要与默认的cache表的结构完全相同。
 
表15-1 cache表的模式
字段*          类型           Null       默认值
cid            varchar(255)    NO          —
data            longblob        YES         —
expire        int             NO          0
created         int             NO          0
headers         text            YES         NULL
serialized     smallint        NO          0
*粗体表示主键;斜体表示索引字段
 
       cid列,存储的是主缓存ID,用于快速取回缓存信息。在Drupal核心中使用缓存ID的例子有,对于页面缓存使用的是页面的URL(比如,http://example.com/?q=node/1),对于主题注册表缓存使用的是一个字符串和一个主题名字(例如,theme_registry:garland),或者甚至可以使用规则的字符串(比如, variables表中内容的缓存,其缓存ID设置为了variables)。这里的重点是,对于正被缓存的项目来说,缓存ID必须是一个唯一的标识符。
       data列,存储的是你想要缓存的信息。对于复杂的数据类型比如数组或者对象,需要使用PHP的serialize()函数进行序列化,从而将其数据结构也保存到数据库中。(Drupal自动帮你实现了这一点)。
       expire列,使用下面的3个值中的一个:
 
       CACHE_PERMANENT:该项目永远不会被删除,只有当调用cahe_clear_all()并明确给出持久化项目的缓存ID时,才会被删除。
 
       CACHE_TEMPORARY:这意味着当下一次不带参数的调用cahe_clear_all()时,该项目就会被删除,而没有最小时间限制。标记为CACHE_PERMANENT的项目此时不会被删除。
 
       一个Unix时间戳:指的是该项目的最小存在时间,在这个最小时间内,该项目就不会被删除,当过了这个时间,它就和标记为CACHE_TEMPORARY的项目一样了。
 
       created列,是一个Unix时间戳,指的是缓存条目创建的日期。
       headers列,用来存储HTTP的响应头部,在缓存数据是一个完整的Drupal页面请求时使用。大多数时候,你不使用这一字段,这是因为你要缓存的是页面的一部分而不是整个页面,也就是说要缓存的数据不依赖于头部。记住,尽管如此,你自定义的缓存表的结构仍然需要和默认的cache表的结构完全相同,所以尽管没有用到它,也要保留它。
    serialized列,指的是data列中的数据是否处于序列化的形态。0表示未序列化的数据,1表示序列化的数据。如果数据被序列化,并且serialized列的值为1,那么缓存系统在将数据返回给调用者以前,会对其进行反序列化。对于对象、数组这种类型的数据,在被缓存时,缓存系统能将其自动的序列化并将serialized列设置为1。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 缓存在Drupal核心中的应用

 

Drupal默认自带了6个缓存表:cache存储了variables表和数据库模式和主题注册表的一个拷贝;cache_block存储了区块的缓存拷贝;cache_menu存储了导航菜单的缓存拷贝;每个节点的内容在被过滤器系统解析后,其缓存拷贝将被存储在cache_filter表中;cache_form用在表单API中,在可能的情况下,用于避免表单的重新构建;cache_page为匿名用户存储了页面的缓存拷贝。我们在接下来的部分中,将会逐一的讲解这些缓存。需要注意的是,在管理界面“管理➤站点配置 ➤性能”中的“页面缓存”和“区块缓存”设置,它们仅仅影响页面缓存和区块缓存表,对于Drupal中的其它缓存部分不起作用。换句话说,过滤器,菜单,和模块设置总是被缓存的。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 菜单系统

 

菜单系统缓存了连接Drupal路径与回调的路由信息。无论是否启用了Drupal的页面缓存,由菜单模块创建的菜单都会被缓存。所以为了清除菜单缓存,可以使用“管理➤站点配置 ➤性能”页面的“清除缓存数据”按钮,或者调用menu_cache_clear_all()。如果你对菜单的修改影响到了区块,你可能需要调用更厉害的menu_rebuild()函数;当菜单被重新构建时,菜单缓存也会被清除。菜单的例子有,Drupal的一级和二级链接,以及用户导航区块。菜单基于单用户、单地域进行缓存。关于菜单系统的更多信息,可参看第4章。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 过滤的输入格式

老葛的Drupal培训班 Think in Drupal

当创建或者编辑一个节点时,节点的内容将经过与其输入格式相关的各种过滤器的处理。例如,HTML过滤器格式将换行转换为了HTML<p>和<br>标签,同时还过滤掉恶意的HTML。如果每次查看一个节点时都进行过滤,那么这会浪费很多资源。因此,只有在刚刚创建或编辑完节点以后才对其应用过滤器(其它时候不用),并将过滤后的内容缓存到cache_filter数据库表中,这一缓存不受Drupal页面缓存是否启用的影响。关于输入格式的更多信息,可参看第11章。
 
提示 当你使用管理界面修改节点摘要的默认长度时,只有当你重新保存每个节点以后才会生效,其原因就在于过滤器缓存。解决该问题的简便方法就是清空cache_filter表,这样所有的节点内容将被重新解析,摘要被重新构建。或者,你可能想清除所有的缓存(包括过滤器缓存),那么可以使用“管理➤站点配置 ➤性能”页面的“清除缓存数据”按钮。
 

Drupal版本:

Drupal专业开发指南 第15章 管理变量和模块设置

Drupal将大多数的管理设置存储在variables表中,并将该表的所有数据缓存到cache表中,以加快查找配置数据的速度。这类变量的例子,包括你站点的名称、评论和用户的设置、以及files目录的位置。所有的这些变量都被缓存到cache表的一行记录当中了,这样在需要每个变量时,就可以快速的将其取回,而不是每次都进行一次数据库查询。它们被存储为一个PHP数组,所以缓存值将被序列化从而保留它的结构。如果一个变量使用variable_set()和variable_get()作为设置器(setter)和读取器(getter)函数,那么将以这种方式来存储和缓存它。

 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 页面

 

我们在前面讨论了很多,不过都是对站点的耗费资源的构件进行缓存,但是Drupal最大的优化是缓存整个页面视图。对于匿名用户,很容易做到这一点,这是因为所有页面对于所有匿名用户都是相同的。然而,对于登录用户,每个页面都是针对用户量身定做的。因此需要采用不同的缓存策略来处理这种情况。
    对于匿名用户,Drupal可以使用单个查询来取回缓存的页面内容,当然它还需要一些其它查询以加载Drupal本身。对于匿名用户的页面缓存,有两种缓存策略供你选择:普通模式和激进模式。当然你也可以禁用页面缓存。通过设置最小缓存有效期,你可以进一步的修改普通模式和激进模式策略。这些设置可以在Drupal管理界面“管理➤站点配置 ➤性能”中找到。该界面如图15-1所示。在接下来的部分中,让我们学习一下每种设置。
15-1.控制页面缓存行为的管理界面
 
禁用
    这将完全禁用页面缓存。通常在开发网站时使用。一般情况下,你都需要启用页面缓存。
 
注意 即使禁用了页面缓存,Drupal仍然缓存用户菜单、过滤后的内容、主题注册表、数据库模式、系统变量。这些构件级别的缓存不会被禁用。
 
普通模式
    与完全不使用缓存相比,普通模式对性能会有巨大提升,因此它是提升一个缓慢的Drupal站点性能的最简单方式之一。让我们仔细的看一下,当启用了普通模式缓存系统时,请求的生命周期。
    为了理解普通模式的页面缓存,你首先需要了解Drupal的引导指令流程。引导指令流程是由各个阶段组成的,这里的阶段就是一些更小的独立的步骤。Drupal利用了这个阶段性的引导指令系统,在提供一个缓存页面时,只需要加载和解析所需的代码,对于无关的代码,则不需要对其进行加载和解析,这样就将数据库查询降到了最小。
    图15-2详细给出了为匿名用户的请求提供一个缓存页面的流程。
15-2 本图展示了当处于Drupal的普通模式缓存设置下,为匿名用户提供缓存页面的请求生命周期。引导指令流程的前面5个阶段与缓存无关,在这里将其加进来是为了保持完整性。*表示一个数据库查询;**表示在该点的数据库查询次数是未知的。
 
    首先,请求进来以后,Web服务器就得执行index.php。在index.php中的第一行PHP代码,就是用来包含文件includes/bootstrap.inc的,该文件包含了加载引导指令的核心函数。接着,index.php会调用drupal_bootstrap()。
    drupal_bootstrap()负责执行每一个引导指令阶段。对于普通模式缓存,我们只需要关心DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE引导指令阶段就可以了。在该阶段,首先会从数据库中取回系统变量。假定缓存策略是普通模式,接下来的一步就是包含文件includes/module.inc。module.inc内部的函数是用来允许Drupal激活模块系统的。接着,Drupal将初始化实现了hook_boot()或者hook_exit()的模块。通过分别调用bootstrap_invoke_all(‘boot’)和bootstrap_invoke_all(‘exit’)来激活这些钩子。例如,统计模块,使用statistics_ exit()函数来追踪页面访问。节流阀模块使用throttle_exit()函数,根据当前的访问量来修改节流阀级别。
 
注意 在一个模块中使用hook_ boot ()或者hook_exit()函数,会为整个站点的性能带来负担,这是由于在处于普通缓存模式下,为访问者提供每个缓存页面时,都需要加载你的模块。当你实现这些钩子时,可用的函数也会受到限制,因为此时还没有加载includes/common.inc。常用函数比如t(),l(),和pager_query()此时都不可用。
 
    Drupal_page_cache_header()通过设置HTTP头部来准备缓存数据。Drupal将把Etag和304头部设置为适当的,这样浏览器就可以使用它们自己的内部缓存机制了,在适当的时候可以避免不必要的HTTP循环请求。如果浏览器发送的头部信息已经请求过它,那么缓存的数据将被发送给浏览器。
 
激进模式
    激进模式完全绕开了对所有模块的加载(如图15-3所示)。这意味着,此时不再为缓存页面调用boot(引导)和exit(退出)钩子了。因为不需要加载模块,所以需要解析的PHP代码少了。而需要执行的数据库查询也少了。如果你启用的模块使用了这些钩子(比如统计模块和节流阀模块),那么在激进模式下,它们可能不会正常工作。在管理界面“管理➤站点配置 ➤性能”,Drupal会给出警告,指出哪些模块可能会受到影响。
 
15-3 当处于Drupal的激进模式缓存设置下,为匿名用户提供缓存页面的请求生命周期,*表示一个数据库查询

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 最小缓存有效期

 

这个设置用来控制你站点上的缓存内容的有效期。当一个用户提交了新的内容时,他/她将能立即看到变化;然而,其他用户只有在过了最小的缓存有效期以后,才能看到新的内容。当然,如果将最小缓存有效期设置为“无”,那么每个人都能立即看到新的内容。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 Fastpath:隐藏的缓存设置

 

fastpath缓存设置不能通过Drupal管理界面进行配置,这是因为它的特性非常高级;fastpath使得程序员能够绕开Drupal,来实现一个高度定制化的缓存方案,比如内存或者基于文件的缓存(参看图15-4).
15-4 当处于Drupal的fastpath模式缓存设置下,为匿名用户提供缓存页面的请求生命周期
 
    第3方模块cacherouter (http://drupal.org/project/cacherouter)就是一个利用fastpath模式的模块。假定你把这个模块安装在了sites/all/modules/contrib中。
    由于fastpath在默认情况下不会创建数据库连接,所以要将所有的配置选项放在你的settings.php文件中:
 
$conf = array(
    'page_cache_fastpath' => TRUE,
    'cache_inc' => './sites/all/modules/contrib/cacherouter/cacherouter.inc',
    ... // More settings here.
);
 
    数组中的第一项,通过将page_cache_fastpath设置为TRUE来启用fastpath模式。这样就启用了fastpath模式,非常简单!第2项用来声明Drupal将要加载的文件,将会使用这个文件来代替includes/cache.inc。在这种情况下,声明的文件就是cacherouter模块将要使用的自定义缓存库。cacherouter模块还需要更多一点的配置;详细可参看http://drupal.org/project/cacherouter
    如果你要加载自己的自定义缓存库,来代替Drupal默认使用的includes/cache.inc库,那么你需要编写你自己的cache_set(),cache_get()和cache_clear_all()函数。
 
注意 一旦启用了fastpath缓存,那么它将覆写在Drupal管理界面中设置的任意缓存选项。
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 区块

老葛的Drupal培训班 Think in Drupal

根据它们的内容,区块也可以被缓存。使用管理界面“管理➤站点配置 ➤性能”,可以启用或者禁用Drupal的区块缓存(参看图15-5)。
 
15-5. 用来控制区块缓存行为的管理界面
 
    当一个模块实现hook_block()时,可以在list操作下,声明区块的缓存能力,这样就能实现区块缓存了。例如,下面是modules/user/user.module的hook_block()实现中的部分代码:
 
function user_block($op = 'list', $delta = 0, $edit = array()) {
    global $user;
 
    if ($op == 'list') {
        $blocks[0]['info'] = t('User login');
        // Not worth caching.
        $blocks[0]['cache'] = BLOCK_NO_CACHE;
 
        $blocks[1]['info'] = t('Navigation');
        // Menu blocks can't be cached because each menu item can have
        // a custom access callback. menu.inc manages its own caching.
        $blocks[1]['cache'] = BLOCK_NO_CACHE;
 
        $blocks[2]['info'] = t('Who\'s new');
 
        // Too dynamic to cache.
        $blocks[3]['info'] = t('Who\'s online');
        $blocks[3]['cache'] = BLOCK_NO_CACHE;
        return $blocks;
    }
    ...
}
 
    在前面的例子中,除了一个区块以外,用户模块提供的所有区块都声明了它们不应该被缓存。“新进用户”区块没有声明缓存选项,这意味着如果管理员启用了区块缓存,接着又启用“新进用户”区块,那么该区块将使用默认缓存设置BLOCK_CACHE_PER_ROLE。这意味着为每一个角色存储一个区块的单独的缓存版本。更精确的说,将为角色的每个联合体存储一个单独的缓存版本;通过把当前用户的角色ID连接起来(参看modules/block/block.module中的_block_get_cache_id()),来创建缓存ID。可以用于区块缓存的常量,参看表15-2
 
15-2.区块缓存的常量
常量                 值     含义
BLOCK_NO_CACHE          -1      这个区块不被缓存。
BLOCK_CACHE_PER_ROLE    1       每个角色看到一个单独的缓存区块。*
BLOCK_CACHE_PER_USER    2       每个用户看到一个单独的缓存区块。
BLOCK_CACHE_PER_PAGE    4       每个页面都有它自己的缓存区块。
BLOCK_CACHE_GLOBAL      8       为所有用户只缓存一次区块。
* 没有为区块声明缓存设置时的默认值
 
    所有被缓存的区块,都是基于单个主题和单个语言进行缓存的。这意味着,当启用了多个主题时,在用户当前使用的主题下,不会出现为其它主题缓存的区块;当启用了多个语言时,在用户当前使用的语言下,不会出现为其它语言缓存的区块。
 
注意 对于超级用户(用户1),区块永远不被缓存。
 
    通过使用PHP的位逻辑运算符,可以联合使用多个区块常量(类似于菜单常量)。例如,书籍模块的hook_block()提供的“书籍导航”区块,就同时使用了BLOCK_CACHE_PER_ROLE和BLOCK_CACHE_PER_PAGE:
 
function book_block($op = 'list', $delta = 0, $edit = array()) {
    $block = array();
    switch ($op) {
        case 'list':
            $block[0]['info'] = t('Book navigation');
            $block[0]['cache'] = BLOCK_CACHE_PER_PAGE | BLOCK_CACHE_PER_ROLE;
            return $block;
...
}
    不能为BLOCK_CACHE_PER_ROLE和BLOCK_CACHE_PER_USER常量使用位逻辑运算符(|),这是因为这两种缓存模式是相互排斥的。

Drupal版本:

Drupal专业开发指南 第15章 静态变量缓存

许多Drupal函数使用一个静态变量来缓存数据。在一个HTTP请求的生命周期内,在第2次调用它时,将会立即返回数据。下面是一个来自于节点模块的例子:

 
function node_get_types($op = 'types', $node = NULL, $reset = FALSE) {
    static $_node_types, $_node_names;
 
    if ($reset || !isset($_node_types)) {
        list($_node_types, $_node_names) = _node_types_build();
    }
    ...
}
    缓存总是有代价的。静态变量缓存的代价就是内存。幸运的是,与数据库CPU循环相比,内存一般还是很富裕的。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 使用缓存API

 

对于模块开发者来说,如果他们想使用缓存API的话,那么就需要掌握两个函数:cache_set()和cache_get()。
 
使用cache_set()缓存数据
    cache_set()用来将数据写入到缓存中。函数签名如下:
 
cache_set($cid, $table = 'cache', $data, $expire = CACHE_PERMANENT, $headers = NULL)
 
函数参数有:
 
    $cid:唯一的缓存ID字符串,用作缓存数据的键。使用冒号来定界可能的层级。
 
$table:用来存储数据的表的名字。你可以创建你自己的表,或者使用cache,cache_block, cache_filter,cache_form,cache_menu, cache_page。默认使用cache表。
 
$data:存储在缓存中的数据。PHP对象和数组将被自动序列化。
 
$expire:缓存数据的有效期的时长。可能值有CACHE_PERMANENT,CACHE_TEMPORARY,或者一个Unix时间戳。如果给定了一个Unix时间戳,并且当前时间超过了该时间戳,那么该数据的处理方式将和标记为CACHE_TEMPORARY的是一样的。
 
$headers:用于缓存的页面,传递给浏览器的HTTP头部字符串。
 
modules/filter/filter.module中,有一个cache_set()示例:
 
// Store in cache with a minimum expiration time of 1 day.
if ($cache) {
    cache_set($cid, 'cache_filter', $text, time() + (60 * 60 * 24));
}
 
使用cache_get()取回缓存的数据
    cache_get()用来取回缓存的数据。函数签名如下:
 
cache_get($cid, $table = 'cache')
而函数参数有:
 
$cid:要取回的数据的缓存ID。
$table:要取回的数据所在的表的名字。你可以创建你自己的表,或者使用cache,cache_block,cache_filter,cache_form,cache_menu,cache_page。默认使用cache表。
 
modules/filter/filter.module中,有一个cache_get()的示例:
 
// Check for a cached version of this piece of text.
if ($cached = cache_get($cid, 'cache_filter')) {
    return $cached->data;
}
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 清除缓存

 

如果你的模块最了解其数据的失效时间,那么它需要负责在一个适当的时间清除缓存。对于缓存的清除,有两个指导原则:
 
• 尽可能的清除特定的缓存。不要因为特定模块数据的一点修改,来清除所有的Drupal缓存!打个比方来说,如果你家厨房的地板脏了,只需要对其进行清扫就可以了,而不需要把家里的所有地毯都掀了并替换掉。
 
• 要尽可能多的重复利用缓存的数据。尽管缓存的要点是,通过减少所需的工作总量,来增加响应能力,但是在清除缓存数据的时候,也是需要花费很多功夫的,特别是有很多缓存数据的时候。
 
    下面的子部分描述了清除缓存数据的一些方式。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 使用$reset参数

 

许多使用静态变量实现内部缓存的Drupal函数,都有一个可选的$reset参数,用来指示该函数清除它的内部缓存。例如,下面是我们熟知的node_load():
 
function node_load($param = array(), $revision = NULL, $reset = NULL) {
    static $nodes = array();
 
    if ($reset) {
        $nodes = array();
    }
    ...
}

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 使用cache_clear_all()

老葛的Drupal培训班 Think in Drupal

用来清除缓存数据的主函数就是includes/cache.inc中的cache_clear_all()。函数的签名如下:
function cache_clear_all($cid = NULL, $table = NULL, $wildcard = FALSE) {...}
 
    参数$cid和$table的含义,与cache_set()和cache_get()中的一样。而参数$wildcard是用来指示是否对$cid采用通配符的形式进行处理,也就是说,把$cid作为一个子字符串,任何从左边匹配的条目将被清除。下面是一些例子。
 
    清除cache表中的特定条目foo:bar:
 
$cid = 'foo:bar';
cache_clear_all($cid, 'cache');
 
    清除cache表中的由foo模块设置的(假定,$cid都采用foo:前缀)任何过期的条目:
 
$cid = 'foo:'; // Will match cache keys foo:bar, foo:baz, etc.
cache_clear_all($cid, 'cache', TRUE);
 
    在前面的例子中,实际运行的数据库查询如下:
 
db_query("DELETE FROM {". $table ."} WHERE cid LIKE '%s%%'", $cid);
 
    如果foo模块将它的数据保存在了它自己的cache_foo表中,那么需要对该表进行声明,这样cache_clear_all()就知道清除哪个表了:
 
$cid = 'foo:bar';
cache_clear_all($cid, 'cache_foo');
 
    如果你想完全清空一个缓存表,那么可以把$cid设为*,把$wildcard设为TRUE。这个例子将清空整个cache_foo表:
 
cache_clear_all('*', 'cache_foo', TRUE);
 
    清除页面和区块缓存(例如,cache_page和cache_block表)的任何过期条目:
 
cache_clear_all();

Drupal版本:

Drupal专业开发指南 第15章 使用hook_flush_caches()

 

Drupal有一个中心函数,用来清空所有的缓存,包括JavaScript和CSS缓存。这就是来自于includes/common.inc的drupal_flush_all_caches()函数:
 
/**
 * Flush all cached data on the site.
 *
 * Empties cache tables, rebuilds the menu cache and theme registries, and
 * exposes a hook for other modules to clear their own cache data as well.
 */
function drupal_flush_all_caches() {
    // Change query-strings on css/js files to enforce reload for all users.
    _drupal_flush_css_js();
    drupal_clear_css_cache();
    drupal_clear_js_cache();
    system_theme_data();
    drupal_rebuild_theme_registry();
    menu_rebuild();
    node_types_rebuild();
    // Don't clear cache_form - in-progress form submissions may break.
    // Ordered so clearing the page cache will always be the last action.
    $core = array('cache', 'cache_block', 'cache_filter', 'cache_page');
    $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
    foreach ($cache_tables as $table) {
        cache_clear_all('*', $table, TRUE);
    }
}
 
    注意包含module_invoke_all('flush_caches')的那行代码。这将触发hook_flush_caches()。如果你使用了自己的缓存表,那么当点击“管理➤站点配置 ➤性能”页面的“清除缓存数据”按钮时,通过实现钩子hook_flush_caches(),你的模块就可以清除自己的缓存了。该按钮的提交处理器调用的就是drupal_flush_all_caches()。hook_flush_caches()的实现非常简单;你的模块只需要简单得返回一个数组,里面包含要被清空的缓存表就可以了。下面是来自更新状态模块的例子:
 
/**
 * Implementation of hook_flush_caches().
 */
function update_flush_caches() {
    return array('cache_update');
}

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第15章 总结

 

在本章,你学到:
    Drupal提供的各种缓存类型:页面、区块、菜单、变量、过滤器缓存
    页面缓存系统的工作原理
    普通模式,激进模式和fastpath模式之间的不同之处
    区块缓存系统的工作原理
缓存API函数
 

老葛的Drupal培训班 Think in Drupal

Drupal版本: