zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

通过缓存数据库结果提高PHP性能的原理介绍

PHP数据库性能缓存原理 介绍 通过 提高
2023-06-13 09:14:35 时间
但当您使用的数据库与Web服务器位于不同的计算机上时,缓存数据库结果集通常是一个不错的方法。不过,根据您的情况确定最佳的缓存策略却是一个难题。例如,对于使用最新数据库结果集比较重要的应用程序而言,时间触发的缓存方法(缓存系统常用的方法,它假设每次到达失效时间戳记时就重新生成缓存)可能并不是一个令人满意的解决方案。这种情况下,您需要采用一种机制,每当应用程序需要缓存的数据库数据发生更改时,该机制将通知该应用程序,以便该应用程序将缓存的过期数据与数据库保持一致。这种情况下使用“数据库更改通知”(一个新的Oracle数据库10g第2版特性)将非常方便。

  “数据库更改通知”入门

  “数据库更改通知”特性的用法非常简单:创建一个针对通知执行的通知处理程序–一个PL/SQL存储过程或客户端OCI回调函数。然后,针对要接收其更改通知的数据库对象注册一个查询,以便每当事务更改其中的任何对象并提交时调用通知处理程序。通常情况下,通知处理程序将被修改的表的名称、所做更改的类型以及所更改行的行ID(可选)发送给客户端监听程序,以便客户端应用程序可以在响应中执行相应的处理。

  为了了解“数据库更改通知”特性的作用方式,请考虑以下示例。假设您的PHP应用程序访问OE.ORDERS表中存储的订单以及OE.ORDER_ITEMS中存储的订单项。鉴于很少更改已下订单的信息,您可能希望应用程序同时缓存针对ORDERS和ORDER_ITEMS表的查询结果集。要避免访问过期数据,您可以使用“数据库更改通知”,它可让您的应用程序方便地获知以上两个表中所存储数据的更改。

  您必须先将CHANGENOTIFICATION系统权限以及EXECUTEONDBMS_CHANGENOTIFICATION权限授予OE用户,才能注册对ORDERS和ORDER_ITEMS表的查询,以便接收通知和响应对这两个表所做的DML或DDL更改。为此,可以从SQL命令行工具(如SQL*Plus)中执行下列命令。

CONNECT/ASSYSDBA;
GRANTCHANGENOTIFICATIONTOoe;
GRANTEXECUTEONDBMS_CHANGE_NOTIFICATIONTOoe;
  确保将init.ora参数job_queue_processes设置为非零值,以便接收PL/SQL通知。或者,您也可以使用下面的ALTERSYSTEM命令:

ALTERSYSTEMSET"job_queue_processes"=2;  然后,在以OE/OE连接后,您可以创建一个通知处理程序。但首先,您必须创建将由通知处理程序使用的数据库对象。例如,您可能需要创建一个或多个数据库表,以便通知处理程序将注册表的更改记录到其中。在以下示例中,您将创建nfresults表来记录以下信息:更改发生的日期和时间、被修改的表的名称以及一个消息(说明通知处理程序是否成功地将通知消息发送给客户端)。

CONNECToe/oe;
CREATETABLEnfresults(
operdateDATE,
tblnameVARCHAR2(60),
rslt_msgVARCHAR2(100)
);
  在实际情况中,您可能需要创建更多表来记录通知事件以及所更改行的行ID等信息,但就本文而言,nfresults表完全可以满足需要。
  使用UTL_HTTP向客户端发送通知
  您可能还要创建一个或多个PL/SQL存储过程,并从通知处理程序中调用这些存储过程,从而实现一个更具可维护性和灵活性的解决方案。例如,您可能要创建一个实现将通知消息发送给客户端的存储过程。“清单1”是PL/SQL过程sendNotification。该过程使用UTL_HTTPPL程序包向客户端应用程序发送更改通知。

  清单1.使用UTL_HTTP向客户端发送通知

复制代码代码如下:

CREATEORREPLACEPROCEDUREsendNotification(urlINVARCHAR2,
tblnameINVARCHAR2,order_idINVARCHAR2)IS
reqUTL_HTTP.REQ;
respUTL_HTTP.RESP;
err_msgVARCHAR2(100);
tblVARCHAR(60);
BEGIN
tbl:=SUBSTR(tblname,INSTR(tblname,".",1,1)+1,60);
BEGIN
req:=UTL_HTTP.BEGIN_REQUEST(url||order_id||"&"||"table="||tbl);
resp:=UTL_HTTP.GET_RESPONSE(req);
INSERTINTOnfresultsVALUES(SYSDATE,tblname,resp.reason_phrase);
UTL_HTTP.END_RESPONSE(resp);
EXCEPTIONWHENOTHERSTHEN
err_msg:=SUBSTR(SQLERRM,1,100);
INSERTINTOnfresultsVALUES(SYSDATE,tblname,err_msg);
END;
COMMIT;
END;
/


  如“清单1”所示,sendNotification以UTL_HTTP.BEGIN_REQUEST函数发出的HTTP请求的形式向客户端发送通知消息。此URL包含ORDERS表中已更改行的order_id。然后,它使用UTL_HTTP.GET_RESPONSE获取客户端发出的响应信息。实际上,sendNotification并不需要处理客户端返回的整个响应,而是只获取一个在RESP记录的reason_phrase字段中存储的简短消息(描述状态代码)。

  创建通知处理程序

  现在,您可以创建一个通知处理程序,它将借助于上面介绍的sendNotification过程向客户端发送更改通知。来看一看“清单2”中的PL/SQL过程orders_nf_callback。

  清单2.处理对OE.ORDERS表所做更改的通知的通知处理程序

复制代码代码如下:

CREATEORREPLACEPROCEDUREorders_nf_callback(ntfndsINSYS.CHNF$_DESC)IS
tblnameVARCHAR2(60);
numtablesNUMBER;
event_typeNUMBER;
row_idVARCHAR2(20);
numrowsNUMBER;
ord_idVARCHAR2(12);
urlVARCHAR2(256):="http://webserverhost/phpcache/dropResults.php?order_no=";
BEGIN
event_type:=ntfnds.event_type;
numtables:=ntfnds.numtables;
IF(event_type=DBMS_CHANGE_NOTIFICATION.EVENT_OBJCHANGE)THEN
FORiIN1..numtablesLOOP
tblname:=ntfnds.table_desc_array(i).table_name;
IF(bitand(ntfnds.table_desc_array(i).opflags,
DBMS_CHANGE_NOTIFICATION.ALL_ROWS)=0)THEN
numrows:=ntfnds.table_desc_array(i).numrows;
ELSE
numrows:=0;
ENDIF;
IF(tblname="OE.ORDERS")THEN
FORjIN1..numrowsLOOP
row_id:=ntfnds.table_desc_array(i).row_desc_array(j).row_id;
SELECTorder_idINTOord_idFROMordersWHERErowid=row_id;
sendNotification(url,tblname,ord_id);
ENDLOOP;
ENDIF;
ENDLOOP;
ENDIF;
COMMIT;
END;
/


  如“清单2”所示,此通知处理程序将SYS.CHNF$_DESC对象用作参数,然后使用它的属性获取该更改的详细信息。在该示例中,此通知处理程序将只处理数据库为响应对注册对象进行的DML或DDL更改(也就是说,仅当通知类型为EVENT_OBJCHANGE时)而发布的通知,并忽略有关其他数据库事件(如实例启动或实例关闭)的通知。从以上版本开始,处理程序可以处理针对OE.ORDERS表中每个受影响的行发出的更改通知。在本文后面的“将表添加到现有注册”部分中,您将向处理程序中添加几行代码,以便它可以处理针对OE.ORDER_ITEMS表中被修改的行发出的通知。

  为更改通知创建注册
  创建通知处理程序后,必须为其创建一个查询注册。对于本示例而言,您必须在注册过程中对OE.ORDER表执行查询并将orders_nf_callback指定为通知处理程序。您还需要在DBMS_CHANGE_NOTIFICATION程序包中指定QOS_ROWIDS选项,以便在通知消息中启用ROWID级别的粒度。“清单3”是一个PL/SQL块,它为orders_nf_callback通知处理程序创建查询注册。

  清单3.为通知处理程序创建查询注册

复制代码代码如下:
DECLARE
REGDSSYS.CHNF$_REG_INFO;
regidNUMBER;
ord_idNUMBER;
qosflagsNUMBER;
BEGIN
qosflags:=DBMS_CHANGE_NOTIFICATION.QOS_RELIABLE+
DBMS_CHANGE_NOTIFICATION.QOS_ROWIDS;
REGDS:=SYS.CHNF$_REG_INFO("orders_nf_callback",qosflags,0,0,0);
regid:=DBMS_CHANGE_NOTIFICATION.NEW_REG_START(REGDS);
SELECTorder_idINTOord_idFROMordersWHEREROWNUM<2;
DBMS_CHANGE_NOTIFICATION.REG_END;
END;
/

  本示例针对ORDERS表创建了一个注册,并将orders_nf_callback用作通知处理程序。现在,如果您使用DML或DDL语句修改ORDERS表并提交事务,则将自动调用orders_nf_callback函数。例如,您可能针对ORDERS表执行下列UPDATE语句并提交该事务:

UPDATEORDERSSETorder_mode="direct"WHEREorder_id=2421;
UPDATEORDERSSETorder_mode="direct"WHEREorder_id=2422;
COMMIT;

  要确保数据库发布了通知来响应以上事务,您可以检查nfresults表:

SELECTTO_CHAR(operdate,"dd-mon-yyhh:mi:ss")operdate,
tblname,rslt_msgFROMnfresults;
  结果应如下所示:

OPERDATETBLNAMERSLT_MSG
-----------------------------------------
02-mar-0604:31:28OE.ORDERSNotFound
02-mar-0604:31:29OE.ORDERSNotFound
  从以上结果中可以清楚地看到,orders_nf_callback已经正常工作,但未找到客户端脚本。在该示例中出现这种情况并不意外,这是因为您并未创建URL中指定的dropResults.php脚本。
  将表添加到现有注册
  前一部分介绍了如何使用更改通知服务使数据库在注册对象(在以上示例中为ORDERS表)发生更改时发出通知。但从性能角度而言,客户端应用程序可能更希望缓存ORDER_ITEMS表而非ORDERS表本身的查询结果集,这是因为它在每次访问订单时,不得不从ORDERS表中只检索一行,但同时必须从ORDER_ITEMS表中检索多个行。在实际情况中,订单可能包含数十个甚至数百个订单项。
  由于您已经对ORDERS表注册了查询,因此不必再创建一个注册来注册对ORDER_ITEMS表的查询了。相反,您可以使用现有注册。为此,您首先需要检索现有注册的ID。可以执行以下查询来完成此工作:

SELECTregid,table_nameFROMuser_change_notification_regs;  结果可能如下所示:

REGIDTABLE_NAME
-------------------
241OE.ORDERS
  获取注册ID后,可以使用DBMS_CHANGE_NOTIFICATION.ENABLE_REG函数将一个新对象添加到该注册,如下所示:
复制代码代码如下:
DECLARE
ord_idNUMBER;
BEGIN
DBMS_CHANGE_NOTIFICATION.ENABLE_REG(241);
SELECTorder_idINTOord_idFROMorder_itemsWHEREROWNUM<2;
DBMS_CHANGE_NOTIFICATION.REG_END;
END;

  完成了!从现在开始,数据库将生成一个通知来响应对ORDERS和ORDER_ITEMS所做的任何更改,并调用orders_nf_callback过程来处理通知。因此,下一步就是编辑orders_nf_callback,以便它可以处理因对ORDER_ITEMS表执行DML操作而生成的通知。但在重新创建orders_nf_callback过程之前,您需要创建以下将在更新过程中引用的表类型:

CREATETYPErdesc_tabASTABLEOFSYS.CHNF$_RDESC;  然后,返回清单,在以下代码行之后:
复制代码代码如下:
IF(tblname="OE.ORDERS")THEN
FORjIN1..numrowsLOOP
row_id:=ntfnds.table_desc_array(i).row_desc_array(j).row_id;
SELECTorder_idINTOord_idFROMordersWHERErowid=row_id;
sendNotification(url,tblname,ord_id);
ENDLOOP;
ENDIF;

  插入以下代码:
复制代码代码如下:
IF(tblname="OE.ORDER_ITEMS")THEN
FORrecIN(SELECTDISTINCT(o.order_id)o_idFROM
TABLE(CAST(ntfnds.table_desc_array(i).row_desc_arrayASrdesc_tab))t,
orderso,order_itemsdWHEREt.row_id=d.rowidANDd.order_id=o.order_id)
LOOP
sendNotification(url,tblname,rec.o_id);
ENDLOOP;
ENDIF;

  重新创建orders_nf_callback后,您需要测试它能否正常工作。为此,您可以针对ORDER_ITEMS表执行下列UPDATE语句并提交该事务:

UPDATEORDER_ITEMSSETquantity=160WHEREorder_id=2421ANDline_item_id=1;
UPDATEORDER_ITEMSSETquantity=160WHEREorder_id=2421ANDline_item_id=2;
COMMIT;
  然后,检查nfresults表,如下所示:

SELECTTO_CHAR(operdate,"dd-mon-yyhh:mi:ss")operdate,
rslt_msgFROMnfresultsWHEREtblname="OE.ORDER_ITEMS";  输出可能如下所示:

OPERDATERSLT_MSG
---------------------------------
03-mar-0612:32:27NotFound
  您可能很奇怪为什么只向nfresults表中插入了一行?毕竟您更新了ORDER_ITEMS表中的两行。实际上,这两个更新了的行具有相同的order_id?即它们属于同一订单。此处,我们假设客户端应用程序将使用一个语句选择订单的所有订单项,因此它并不需要确切知道已经更改了某个订单的哪些订单项。相反,客户端需要知道其中至少修改、删除或插入了一个订单项的订单ID。
  构建客户端
  现在,您已经针对ORDERS和ORDER_ITEMS表创建了注册,下面我们将了解一下访问这些表中存储的订单及其订单项的客户端应用程序如何使用更改通知。为此,您可以构建一个PHP应用程序,它将缓存针对以上表的查询结果,并采取相应的操作来响应有关对这些表所做更改的通知(从数据库服务器中收到这些通知)。一个简单的方法是使用PEAR::Cache_Lite程序包,它为您提供了一个可靠的机制来使缓存数据保持最新状态。尤其是,您可以使用Cache_Lite_Function类(PEAR::Cache_Lite程序包的一部分),通过该类您可以缓存函数调用。
  例如,您可以创建一个函数来执行下列任务:建立数据库连接、针对该数据库执行select语句、获取检索结果并最终以数组形式返回结果。然后,您可以通过Cache_Lite_Function实例的call方法缓存由该函数返回的结果数组,以便可以从本地缓存而不是从后端数据库读取这些数组,这样可以显著提高应用程序的性能。然后,在收到缓存数据更改的通知时,您将使用Cache_Lite_Function实例的drop方法删除缓存中的过期数据。
  回过头来看看本文的示例,您可能要创建两个函数,用于应用程序与数据库交互:第一个函数将查询ORDERS表并返回具有指定ID的订单,而另一个函数将查询ORDER_ITEMS表并返回该订单的订单项。“清单4”显示了包含getOrderFields函数(该函数接受订单ID并返回一个包含所检索到订单的某些字段的关联数组)的getOrderFields.php脚本。

  清单4.获取指定订单的字段

复制代码代码如下:
<?php
//File:getOrderFields.php
require_once"connect.php";
functiongetOrderFields($order_no){
if(!$rsConnection=GetConnection()){
returnfalse;
}
$strSQL="SELECTTO_CHAR(ORDER_DATE)ORDER_DATE,CUSTOMER_ID,
ORDER_TOTALFROMORDERSWHEREorder_id=:order_no";
$rsStatement=oci_parse($rsConnection,$strSQL);
oci_bind_by_name($rsStatement,":order_no",$order_no,12);
if(!oci_execute($rsStatement)){
$err=oci_error();
print$err["message"];
trigger_error("Queryfailed:".$err["message"]);
returnfalse;
}
$results=oci_fetch_assoc($rsStatement);
return$results;
}
?>

  “清单5”是getOrderItems.php脚本。该脚本包含getOrderItems函数,该函数接受订单ID并返回一个二维数组,该数组包含表示订单的订单项的行。

  清单5.获取指定订单的订单项

复制代码代码如下:
<?php
//File:getOrderItems.php
require_once"connect.php";
functiongetOrderItems($order_no){
if(!$rsConnection=GetConnection()){
returnfalse;
}
$strSQL="SELECT*FROMORDER_ITEMSWHERE
order_id=:order_noORDERBYline_item_id";
$rsStatement=oci_parse($rsConnection,$strSQL);
oci_bind_by_name($rsStatement,":order_no",$order_no,12);
if(!oci_execute($rsStatement)){
$err=oci_error();
trigger_error("Queryfailed:".$err["message"]);
returnfalse;
}
$nrows=oci_fetch_all($rsStatement,$results);
returnarray($nrows,$results);
}
?>

  注意,以上两个函数都需要connect.php脚本,该脚本应包含返回数据库连接的GetConnection函数。清单6就是connect.php脚本:

  清单6.获取数据库连接

复制代码代码如下:
<?php
//File:connect.php
functionGetConnection(){
$dbHost="dbserverhost";
$dbHostPort="1521";
$dbServiceName="orclR2";
$usr="oe";
$pswd="oe";
$dbConnStr="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$dbHost.")
(PORT=".$dbHostPort."))(CONNECT_DATA=(SERVICE_NAME=".$dbServiceName.")))";
if(!$dbConn=oci_connect($usr,$pswd,$dbConnStr)){
$err=oci_error();
trigger_error("Failedtoconnect".$err["message"]);
returnfalse;
}
return$dbConn;
}
?>

  现在,您已经创建了与数据库通信所需的所有函数,下面我们将了解一下Cache_Lite_Function类的工作方式。清单7是testCache.php脚本,该脚本使用Cache_Lite_Function类缓存以上函数的结果。

  清单7.使用PEAR::Cache_Lite缓存

复制代码代码如下:
<?php
//File:testCache.php
require_once"getOrderItems.php";
require_once"getOrderFields.php";
require_once"Cache/Lite/Function.php";
$options=array(
"cacheDir"=>"/tmp/",
"lifeTime"=>86400
);
if(!isset($_GET["order_no"])){
die("Theorder_noparameterisrequired");
}
$order_no=$_GET["order_no"];
$cache=newCache_Lite_Function($options);
if($orderfields=$cache->call("getOrderFields",$order_no)){
print"<h3>ORDER#$order_no</h3>\n";
print"<table>";
print"<tr><td>DATE:</td><td>".$orderfields["ORDER_DATE"]."</td></tr>";
print"<tr><td>CUST_ID:</td><td>".$orderfields["CUSTOMER_ID"]."</td></tr>";
print"<tr><td>TOTAL:</td><td>".$orderfields["ORDER_TOTAL"]."</td></tr>";
print"</table>";
}else{
print"Someproblemoccurredwhilegettingorderfields!\n";
$cache->drop("getOrderFields",$order_no);
}
if(list($nrows,$orderitems)=$cache->call("getOrderItems",$order_no)){
//print"<h3>LINEITEMSINORDER#$order_no</h3>";
print"<tableborder=1>";
print"<tr>\n";
while(list($key,$value)=each($orderitems)){
print"<th>$key</th>\n";
}
print"</tr>\n";
for($i=0;$i<$nrows;$i++){
print"<tr>";
print"<td>".$orderitems["ORDER_ID"][$i]."</td>";
print"<td>".$orderitems["LINE_ITEM_ID"][$i]."</td>";
print"<td>".$orderitems["PRODUCT_ID"][$i]."</td>";
print"<td>".$orderitems["UNIT_PRICE"][$i]."</td>";
print"<td>".$orderitems["QUANTITY"][$i]."</td>";
print"</tr>";
}
print"</table>";
}else{
print"Someproblemoccurredwhilegettingorderlineitems";
$cache->drop("getOrderItems",$order_no);
}
?>

  “清单7”中的testCache.php脚本应与order_noURL参数(代表OE.ORDER表中存储的订单ID)一起被调用。例如,要检索与ID为2408的订单相关的信息,需要在浏览器中输入如下所示的URL:

http://webserverhost/phpcache/testCache.php?order_no=2408  结果,浏览器将生成以下输出:
  ORDER#2408

DATE:29-JUN-9906.59.31.333617AM
CUST_ID:166
TOTAL:309
ORDER_IDLINE_ITEM_IDPRODUCT_IDUNIT_PRICEQUANTITY
240812751613
240822761261
2408327831010

  现在,如果您单击浏览器中的reload按钮,testCache.php脚本将不会再次调用getOrderFields和getOrderItems函数。相反,它将从本地缓存中读取它们的结果。因此,从现在起的24小时(因为lifeTime设置为86400秒)以内,本地缓存即可满足使用order_no=2108的每个getOrderFields或getOrderItems调用的需要。但请注意,Cache_Lite_Function类未提供API来测试具有给定参数的给定函数是否存在可用缓存。因此,要确定每次使用相同参数调用函数时应用程序是实际上读取缓存还是仍执行该函数可能有点棘手。例如,在以上示例中,要确保缓存机制正常工作,您可以临时更改connect.php脚本中指定的连接信息,以便它无法建立数据库连接;比如指定一个错误的数据库服务器主机名称,然后再次使用order_no=2108运行testCache.php脚本。如果缓存正常工作,浏览器的输出应与先前的一样。

  此外,您还可以检查缓存目录,该目录作为cacheDir选项的值(在该示例中为/tmp)传递给Cache_Lite_Function类的构造函数。在该目录中,您将找到两个刚创建的缓存文件,这些文件的名称类似于:cache_7b181b55b55aee36ad5e7bd9d5a091ec_3ad04d3024f4cd54296f75c92a359154。注意,如果您是一位Windows用户,则可能要使用%SystemDrive%\temp目录保存缓存文件。如果是这样,则必须将cacheDir选项设置为/temp/。

  验证缓存机制正常工作后,可以接着创建一个PHP来处理从数据库服务器收到的更改通知。“清单8”是dropResult.php脚本。数据库服务器将调用该脚本来响应ORDERS和ORDER_ITEMS表的更改。

  清单8.处理从数据库服务器收到的更改通知

复制代码代码如下:
<?php
//File:dropResults.php
require_once"Cache/Lite/Function.php";
$options=array(
"cacheDir"=>"/tmp/"
);
$cache=newCache_Lite_Function($options);
if(isset($_GET["order_no"])&&isset($_GET["table"])){
if($_GET["table"]=="ORDER_ITEMS"){
$cache->drop("getOrderItems",$_GET["order_no"]);
}
if($_GET["table"]=="ORDERS"){
$cache->drop("getOrderFields",$_GET["order_no"]);
}
}
?>


  创建dropResult.php脚本后,请确保在通知处理程序中指定的URL(如清单2所示)正确。然后,在SQL*Plus或类似工具中以OE/OE连接,并执行UPDATE语句,这些语句将影响本部分先前通过testCache.php脚本访问的同一订单(此处是ID为2408的订单):

UPDATEORDERSSETorder_mode="direct"WHEREorder_id=2408;
UPDATEORDER_ITEMSSETquantity=3WHEREorder_id=2408ANDline_item_id=1;
UPDATEORDER_ITEMSSETquantity=1WHEREorder_id=2408ANDline_item_id=2;
COMMIT;
  为响应以上更新,本文前面介绍的通知处理程序将逐个使用下列URL运行dropResults.php脚本两次:

http://webserverhost/phpcache/dropResults.php?order_no=2408&table=ORDERS
http://webserverhost/phpcache/dropresults.php?order_no=2408&table=ORDER_ITEMS
  从“清单8”中您可以清楚地看到,dropResult.php脚本在从数据库服务器收到更改通知后并未刷新缓存。它只是删除了包含过期数据的缓存文件。因此,如果现在检查缓存目录,则将看到在使用order_no=2408运行testCache.php脚本时创建的缓存文件已经消失。这实际上意味着,testCache.php在下次请求与ID为2408的订单相关的数据时将从后端数据库而非本地缓存中获取该数据。

  您会发现,在应用程序请求的结果集很有可能在应用程序使用它之前更改的情况下该方法将很有用。就本文的示例而言,这意味着与特定订单相关的数据可能在testCache.php访问该订单之前多次更改。这样,应用程序会因在从数据库服务器收到更改通知后立即刷新它的缓存而做了大量不必要的工作。

  但如果您希望dropResult.php脚本在收到更改通知后立即刷新缓存,则可以在调用drop方法后调用Cache_Lite_Function实例的call方法,并为这两个调用指定相同的参数。在该情形下,还应确保包含getOrderFields.php和getOrderItems.php脚本,以便dropResults.php可以调用getOrderFields和getOrderItems函数来刷新缓存。“清单9”是修改后的dropResult.php脚本。

  清单9.在收到更改通知后立即刷新缓存

复制代码代码如下:
<?php
//File:dropResults.php
require_once"Cache/Lite/Function.php";
require_once"getOrderItems.php";
require_once"getOrderFields.php";
$options=array(
"cacheDir"=>"/tmp/",
"lifeTime"=>86400
);
$cache=newCache_Lite_Function($options);
if(isset($_GET["order_no"])&&isset($_GET["table"])){
if($_GET["table"]=="ORDER_ITEMS"){
$cache->drop("getOrderItems",$_GET["order_no"]);
$cache->call("getOrderItems",$_GET["order_no"]);
}
if($_GET["table"]=="ORDERS"){
$cache->drop("getOrderFields",$_GET["order_no"]);
$cache->call("getOrderFields",$_GET["order_no"]);
}
}
?>

  如果存储在ORDERS和ORDER_ITEMS表中的数据很少更改并且应用程序频繁访问它,则以上方法可能很有用。

  总结

  如果PHP应用程序与Oracle数据库10g第2版交互,则可以利用“数据库更改通知特性”,通过该特性应用程序可以接收通知来响应对与发出的请求关联的对象进行的DML更改。使用该特性,您不必在特定时间段更新应用程序中的缓存。相反,仅当注册查询的结果集已经更改时才执行该操作。