国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Table of Contents
ORDER #$order_no
LINE ITEMS IN ORDER #$order_no
Home php教程 php手冊 通過緩存數(shù)據(jù)庫結(jié)果提高PHP性能的原理介紹

通過緩存數(shù)據(jù)庫結(jié)果提高PHP性能的原理介紹

Jun 13, 2016 am 11:58 AM
php web different and introduce principle performance improve database server use of result cache pass

但當(dāng)您使用的數(shù)據(jù)庫與 Web 服務(wù)器位于不同的計算機(jī)上時,緩存數(shù)據(jù)庫結(jié)果集通常是一個不錯的方法。不過,根據(jù)您的情況確定最佳的緩存策略卻是一個難題。例如,對于使用最新數(shù)據(jù)庫結(jié)果集比較重要的應(yīng)用程序而言,時間觸發(fā)的緩存方法(緩存系統(tǒng)常用的方法,它假設(shè)每次到達(dá)失效時間戳記時就重新生成緩存)可能并不是一個令人滿意的解決方案。這種情況下,您需要采用一種機(jī)制,每當(dāng)應(yīng)用程序需要緩存的數(shù)據(jù)庫數(shù)據(jù)發(fā)生更改時,該機(jī)制將通知該應(yīng)用程序,以便該應(yīng)用程序?qū)⒕彺娴倪^期數(shù)據(jù)與數(shù)據(jù)庫保持一致。這種情況下使用“數(shù)據(jù)庫更改通知”(一個新的 Oracle 數(shù)據(jù)庫 10g 第 2 版特性)將非常方便。

  “數(shù)據(jù)庫更改通知”入門

  “數(shù)據(jù)庫更改通知”特性的用法非常簡單:創(chuàng)建一個針對通知執(zhí)行的通知處理程序 – 一個 PL/SQL 存儲過程或客戶端 OCI 回調(diào)函數(shù)。然后,針對要接收其更改通知的數(shù)據(jù)庫對象注冊一個查詢,以便每當(dāng)事務(wù)更改其中的任何對象并提交時調(diào)用通知處理程序。通常情況下,通知處理程序?qū)⒈恍薷牡谋淼拿Q、所做更改的類型以及所更改行的行 ID(可選)發(fā)送給客戶端監(jiān)聽程序,以便客戶端應(yīng)用程序可以在響應(yīng)中執(zhí)行相應(yīng)的處理。

  為了了解“數(shù)據(jù)庫更改通知”特性的作用方式,請考慮以下示例。假設(shè)您的 PHP 應(yīng)用程序訪問 OE.ORDERS 表中存儲的訂單以及 OE.ORDER_ITEMS 中存儲的訂單項(xiàng)。鑒于很少更改已下訂單的信息,您可能希望應(yīng)用程序同時緩存針對 ORDERS 和 ORDER_ITEMS 表的查詢結(jié)果集。要避免訪問過期數(shù)據(jù),您可以使用“數(shù)據(jù)庫更改通知”,它可讓您的應(yīng)用程序方便地獲知以上兩個表中所存儲數(shù)據(jù)的更改。

  您必須先將 CHANGE NOTIFICATION 系統(tǒng)權(quán)限以及 EXECUTE ON DBMS_CHANGENOTIFICATION 權(quán)限授予 OE 用戶,才能注冊對 ORDERS 和 ORDER_ITEMS 表的查詢,以便接收通知和響應(yīng)對這兩個表所做的 DML 或 DDL 更改。為此,可以從 SQL 命令行工具(如 SQL*Plus)中執(zhí)行下列命令。

CONNECT / AS SYSDBA;
GRANT CHANGE NOTIFICATION TO oe;
GRANT EXECUTE ON DBMS_CHANGE_NOTIFICATION TO oe;
  確保將 init.ora 參數(shù) job_queue_processes 設(shè)置為非零值,以便接收 PL/SQL 通知?;蛘?,您也可以使用下面的 ALTER SYSTEM 命令:

ALTER SYSTEM SET "job_queue_processes"=2;  然后,在以 OE/OE 連接后,您可以創(chuàng)建一個通知處理程序。但首先,您必須創(chuàng)建將由通知處理程序使用的數(shù)據(jù)庫對象。例如,您可能需要創(chuàng)建一個或多個數(shù)據(jù)庫表,以便通知處理程序?qū)⒆员淼母挠涗浀狡渲?。在以下示例中,您將?chuàng)建 nfresults 表來記錄以下信息:更改發(fā)生的日期和時間、被修改的表的名稱以及一個消息(說明通知處理程序是否成功地將通知消息發(fā)送給客戶端)。

CONNECT oe/oe;
CREATE TABLE nfresults (
operdate DATE,
tblname VARCHAR2(60),
rslt_msg VARCHAR2(100)
);
  在實(shí)際情況中,您可能需要創(chuàng)建更多表來記錄通知事件以及所更改行的行 ID 等信息,但就本文而言,nfresults 表完全可以滿足需要。
  使用 UTL_HTTP 向客戶端發(fā)送通知
  您可能還要創(chuàng)建一個或多個 PL/SQL 存儲過程,并從通知處理程序中調(diào)用這些存儲過程,從而實(shí)現(xiàn)一個更具可維護(hù)性和靈活性的解決方案。例如,您可能要創(chuàng)建一個實(shí)現(xiàn)將通知消息發(fā)送給客戶端的存儲過程。“清單 1”是 PL/SQL 過程 sendNotification。該過程使用 UTL_HTTPPL 程序包向客戶端應(yīng)用程序發(fā)送更改通知。

  清單 1. 使用 UTL_HTTP 向客戶端發(fā)送通知

復(fù)制代碼 代碼如下:


CREATE OR REPLACE PROCEDURE sendNotification(url IN VARCHAR2,
tblname IN VARCHAR2, order_id IN VARCHAR2) IS
req UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
err_msg VARCHAR2(100);
tbl VARCHAR(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);
INSERT INTO nfresults VALUES(SYSDATE, tblname, resp.reason_phrase);
UTL_HTTP.END_RESPONSE(resp);
EXCEPTION WHEN OTHERS THEN
err_msg := SUBSTR(SQLERRM, 1, 100);
INSERT INTO nfresults VALUES(SYSDATE, tblname, err_msg);
END;
COMMIT;
END;
/



  如“清單 1”所示,sendNotification 以 UTL_HTTP.BEGIN_REQUEST 函數(shù)發(fā)出的 HTTP 請求的形式向客戶端發(fā)送通知消息。此 URL 包含 ORDERS 表中已更改行的 order_id。然后,它使用 UTL_HTTP.GET_RESPONSE 獲取客戶端發(fā)出的響應(yīng)信息。實(shí)際上,sendNotification 并不需要處理客戶端返回的整個響應(yīng),而是只獲取一個在 RESP 記錄的 reason_phrase 字段中存儲的簡短消息(描述狀態(tài)代碼)。

  創(chuàng)建通知處理程序

  現(xiàn)在,您可以創(chuàng)建一個通知處理程序,它將借助于上面介紹的 sendNotification 過程向客戶端發(fā)送更改通知。來看一看“清單 2”中的 PL/SQL 過程 orders_nf_callback。

  清單 2. 處理對 OE.ORDERS 表所做更改的通知的通知處理程序

復(fù)制代碼 代碼如下:


CREATE OR REPLACE PROCEDURE orders_nf_callback (ntfnds IN SYS.CHNF$_DESC) IS
tblname VARCHAR2(60);
numtables NUMBER;
event_type NUMBER;
row_id VARCHAR2(20);
numrows NUMBER;
ord_id VARCHAR2(12);
url VARCHAR2(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
FOR i IN 1..numtables LOOP
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;
END IF;
IF (tblname = 'OE.ORDERS') THEN
FOR j IN 1..numrows LOOP
row_id := ntfnds.table_desc_array(i).row_desc_array(j).row_id;
SELECT order_id INTO ord_id FROM orders WHERE rowid = row_id;
sendNotification(url, tblname, ord_id);
END LOOP;
END IF;
END LOOP;
END IF;
COMMIT;
END;
/



  如“清單 2”所示,此通知處理程序?qū)?SYS.CHNF$_DESC 對象用作參數(shù),然后使用它的屬性獲取該更改的詳細(xì)信息。在該示例中,此通知處理程序?qū)⒅惶幚頂?shù)據(jù)庫為響應(yīng)對注冊對象進(jìn)行的 DML 或 DDL 更改(也就是說,僅當(dāng)通知類型為 EVENT_OBJCHANGE 時)而發(fā)布的通知,并忽略有關(guān)其他數(shù)據(jù)庫事件(如實(shí)例啟動或?qū)嵗P(guān)閉)的通知。從以上版本開始,處理程序可以處理針對 OE.ORDERS 表中每個受影響的行發(fā)出的更改通知。在本文后面的“將表添加到現(xiàn)有注冊”部分中,您將向處理程序中添加幾行代碼,以便它可以處理針對 OE.ORDER_ITEMS 表中被修改的行發(fā)出的通知。

  為更改通知創(chuàng)建注冊
  創(chuàng)建通知處理程序后,必須為其創(chuàng)建一個查詢注冊。對于本示例而言,您必須在注冊過程中對 OE.ORDER 表執(zhí)行查詢并將 orders_nf_callback 指定為通知處理程序。您還需要在 DBMS_CHANGE_NOTIFICATION 程序包中指定 QOS_ROWIDS 選項(xiàng),以便在通知消息中啟用 ROWID 級別的粒度?!扒鍐?3”是一個 PL/SQL 塊,它為 orders_nf_callback 通知處理程序創(chuàng)建查詢注冊。

  清單 3. 為通知處理程序創(chuàng)建查詢注冊

復(fù)制代碼 代碼如下:


DECLARE
REGDS SYS.CHNF$_REG_INFO;
regid NUMBER;
ord_id NUMBER;
qosflags NUMBER;
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);
SELECT order_id INTO ord_id FROM orders WHERE ROWNUMDBMS_CHANGE_NOTIFICATION.REG_END;
END;
/


  本示例針對 ORDERS 表創(chuàng)建了一個注冊,并將 orders_nf_callback 用作通知處理程序?,F(xiàn)在,如果您使用 DML 或 DDL 語句修改 ORDERS 表并提交事務(wù),則將自動調(diào)用 orders_nf_callback 函數(shù)。例如,您可能針對 ORDERS 表執(zhí)行下列 UPDATE 語句并提交該事務(wù):

UPDATE ORDERS SET order_mode = 'direct' WHERE order_id=2421;
UPDATE ORDERS SET order_mode = 'direct' WHERE order_id=2422;
COMMIT;

  要確保數(shù)據(jù)庫發(fā)布了通知來響應(yīng)以上事務(wù),您可以檢查 nfresults 表:

SELECT TO_CHAR(operdate, 'dd-mon-yy hh:mi:ss') operdate,
tblname, rslt_msg FROM nfresults;
  結(jié)果應(yīng)如下所示:

OPERDATE TBLNAME RSLT_MSG
--------------------- ----------- ---------
02-mar-06 04:31:28 OE.ORDERS Not Found
02-mar-06 04:31:29 OE.ORDERS Not Found
  從以上結(jié)果中可以清楚地看到,orders_nf_callback 已經(jīng)正常工作,但未找到客戶端腳本。在該示例中出現(xiàn)這種情況并不意外,這是因?yàn)槟⑽磩?chuàng)建 URL 中指定的 dropResults.php 腳本。
  將表添加到現(xiàn)有注冊
  前一部分介紹了如何使用更改通知服務(wù)使數(shù)據(jù)庫在注冊對象(在以上示例中為 ORDERS 表)發(fā)生更改時發(fā)出通知。但從性能角度而言,客戶端應(yīng)用程序可能更希望緩存 ORDER_ITEMS 表而非 ORDERS 表本身的查詢結(jié)果集,這是因?yàn)樗诿看卧L問訂單時,不得不從 ORDERS 表中只檢索一行,但同時必須從 ORDER_ITEMS 表中檢索多個行。在實(shí)際情況中,訂單可能包含數(shù)十個甚至數(shù)百個訂單項(xiàng)。
  由于您已經(jīng)對 ORDERS 表注冊了查詢,因此不必再創(chuàng)建一個注冊來注冊對 ORDER_ITEMS 表的查詢了。相反,您可以使用現(xiàn)有注冊。為此,您首先需要檢索現(xiàn)有注冊的 ID??梢詧?zhí)行以下查詢來完成此工作:

SELECT regid, table_name FROM user_change_notification_regs;  結(jié)果可能如下所示:

REGID TABLE_NAME
----- --------------
241 OE.ORDERS
  獲取注冊 ID 后,可以使用 DBMS_CHANGE_NOTIFICATION.ENABLE_REG 函數(shù)將一個新對象添加到該注冊,如下所示:

復(fù)制代碼 代碼如下:


DECLARE
ord_id NUMBER;
BEGIN
DBMS_CHANGE_NOTIFICATION.ENABLE_REG(241);
SELECT order_id INTO ord_id FROM order_items WHERE ROWNUM DBMS_CHANGE_NOTIFICATION.REG_END;
END;


  完成了!從現(xiàn)在開始,數(shù)據(jù)庫將生成一個通知來響應(yīng)對 ORDERS 和 ORDER_ITEMS 所做的任何更改,并調(diào)用 orders_nf_callback 過程來處理通知。因此,下一步就是編輯 orders_nf_callback,以便它可以處理因?qū)?ORDER_ITEMS 表執(zhí)行 DML 操作而生成的通知。但在重新創(chuàng)建 orders_nf_callback 過程之前,您需要創(chuàng)建以下將在更新過程中引用的表類型:

CREATE TYPE rdesc_tab AS TABLE OF SYS.CHNF$_RDESC;  然后,返回清單,在以下代碼行之后:

復(fù)制代碼 代碼如下:


IF (tblname = 'OE.ORDERS') THEN
FOR j IN 1..numrows LOOP
row_id := ntfnds.table_desc_array(i).row_desc_array(j).row_id;
SELECT order_id INTO ord_id FROM orders WHERE rowid = row_id;
sendNotification(url, tblname, ord_id);
END LOOP;
END IF;


  插入以下代碼:

復(fù)制代碼 代碼如下:


IF (tblname = 'OE.ORDER_ITEMS') THEN
FOR rec IN (SELECT DISTINCT(o.order_id) o_id FROM
TABLE(CAST(ntfnds.table_desc_array(i).row_desc_array AS rdesc_tab)) t,
orders o, order_items d WHERE t.row_id = d.rowid AND d.order_id=o.order_id)
LOOP
sendNotification(url, tblname, rec.o_id);
END LOOP;
END IF;


  重新創(chuàng)建 orders_nf_callback 后,您需要測試它能否正常工作。為此,您可以針對 ORDER_ITEMS 表執(zhí)行下列 UPDATE 語句并提交該事務(wù):

UPDATE ORDER_ITEMS SET quantity = 160 WHERE order_id=2421 AND line_item_id=1;
UPDATE ORDER_ITEMS SET quantity = 160 WHERE order_id=2421 AND line_item_id=2;
COMMIT;
  然后,檢查 nfresults 表,如下所示:

SELECT TO_CHAR(operdate, 'dd-mon-yy hh:mi:ss') operdate,
rslt_msg FROM nfresults WHERE tblname = 'OE.ORDER_ITEMS';  輸出可能如下所示:

OPERDATE RSLT_MSG
------------------- --------------
03-mar-06 12:32:27 Not Found
  您可能很奇怪為什么只向 nfresults 表中插入了一行 – 畢竟您更新了 ORDER_ITEMS 表中的兩行。實(shí)際上,這兩個更新了的行具有相同的 order_id – 即它們屬于同一訂單。此處,我們假設(shè)客戶端應(yīng)用程序?qū)⑹褂靡粋€語句選擇訂單的所有訂單項(xiàng),因此它并不需要確切知道已經(jīng)更改了某個訂單的哪些訂單項(xiàng)。相反,客戶端需要知道其中至少修改、刪除或插入了一個訂單項(xiàng)的訂單 ID。
  構(gòu)建客戶端
  現(xiàn)在,您已經(jīng)針對 ORDERS 和 ORDER_ITEMS 表創(chuàng)建了注冊,下面我們將了解一下訪問這些表中存儲的訂單及其訂單項(xiàng)的客戶端應(yīng)用程序如何使用更改通知。為此,您可以構(gòu)建一個 PHP 應(yīng)用程序,它將緩存針對以上表的查詢結(jié)果,并采取相應(yīng)的操作來響應(yīng)有關(guān)對這些表所做更改的通知(從數(shù)據(jù)庫服務(wù)器中收到這些通知)。一個簡單的方法是使用 PEAR::Cache_Lite 程序包,它為您提供了一個可靠的機(jī)制來使緩存數(shù)據(jù)保持最新狀態(tài)。尤其是,您可以使用 Cache_Lite_Function 類(PEAR::Cache_Lite 程序包的一部分),通過該類您可以緩存函數(shù)調(diào)用。
  例如,您可以創(chuàng)建一個函數(shù)來執(zhí)行下列任務(wù):建立數(shù)據(jù)庫連接、針對該數(shù)據(jù)庫執(zhí)行 select 語句、獲取檢索結(jié)果并最終以數(shù)組形式返回結(jié)果。然后,您可以通過 Cache_Lite_Function 實(shí)例的 call 方法緩存由該函數(shù)返回的結(jié)果數(shù)組,以便可以從本地緩存而不是從后端數(shù)據(jù)庫讀取這些數(shù)組,這樣可以顯著提高應(yīng)用程序的性能。然后,在收到緩存數(shù)據(jù)更改的通知時,您將使用 Cache_Lite_Function 實(shí)例的 drop 方法刪除緩存中的過期數(shù)據(jù)。
  回過頭來看看本文的示例,您可能要創(chuàng)建兩個函數(shù),用于應(yīng)用程序與數(shù)據(jù)庫交互:第一個函數(shù)將查詢 ORDERS 表并返回具有指定 ID 的訂單,而另一個函數(shù)將查詢 ORDER_ITEMS 表并返回該訂單的訂單項(xiàng)。“清單 4”顯示了包含 getOrderFields 函數(shù)(該函數(shù)接受訂單 ID 并返回一個包含所檢索到訂單的某些字段的關(guān)聯(lián)數(shù)組)的 getOrderFields.php 腳本。

  清單 4. 獲取指定訂單的字段

復(fù)制代碼 代碼如下:


//File:getOrderFields.php
require_once 'connect.php';
function getOrderFields($order_no) {
if (!$rsConnection = GetConnection()){
return false;
}
$strSQL = "SELECT TO_CHAR(ORDER_DATE) ORDER_DATE, CUSTOMER_ID,
ORDER_TOTAL FROM ORDERS WHERE order_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('Query failed:' . $err['message']);
return false;
}
$results = oci_fetch_assoc($rsStatement);
return $results;
}
?>


  “清單 5”是 getOrderItems.php 腳本。該腳本包含 getOrderItems 函數(shù),該函數(shù)接受訂單 ID 并返回一個二維數(shù)組,該數(shù)組包含表示訂單的訂單項(xiàng)的行。

  清單 5. 獲取指定訂單的訂單項(xiàng)

復(fù)制代碼 代碼如下:


//File:getOrderItems.php
require_once 'connect.php';
function getOrderItems($order_no) {
if (!$rsConnection = GetConnection()){
return false;
}
$strSQL = "SELECT * FROM ORDER_ITEMS WHERE
order_id =:order_no ORDER BY line_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('Query failed:' . $err['message']);
return false;
}
$nrows = oci_fetch_all($rsStatement, $results);
return array ($nrows, $results);
}
?>


  注意,以上兩個函數(shù)都需要 connect.php 腳本,該腳本應(yīng)包含返回數(shù)據(jù)庫連接的 GetConnection 函數(shù)。清單 6 就是 connect.php 腳本:

  清單 6. 獲取數(shù)據(jù)庫連接

復(fù)制代碼 代碼如下:


//File:connect.php
function GetConnection() {
$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('Failed to connect ' .$err['message']);
return false;
}
return $dbConn;
}
?>


  現(xiàn)在,您已經(jīng)創(chuàng)建了與數(shù)據(jù)庫通信所需的所有函數(shù),下面我們將了解一下 Cache_Lite_Function 類的工作方式。清單 7 是 testCache.php 腳本,該腳本使用 Cache_Lite_Function 類緩存以上函數(shù)的結(jié)果。

  清單 7. 使用 PEAR::Cache_Lite 緩存

復(fù)制代碼 代碼如下:


//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('The order_no parameter is required');
}
$order_no=$_GET['order_no'];
$cache = new Cache_Lite_Function($options);
if ($orderfields = $cache->call('getOrderFields', $order_no)){
print "

ORDER #$order_no

\n";
print "";
print "";
print "";
print "";
print "
DATE: ".$orderfields['ORDER_DATE']."
CUST_ID: ".$orderfields['CUSTOMER_ID']."
TOTAL: ".$orderfields['ORDER_TOTAL']."
";
} else {
print "Some problem occurred while getting order fields!\n";
$cache->drop('getOrderFields', $order_no);
}
if (list($nrows, $orderitems) = $cache->call('getOrderItems', $order_no)){
//print "

LINE ITEMS IN ORDER #$order_no

";
print "";
print "\n";
while (list($key, $value) = each($orderitems)) {
print "\n";
}
print "\n";
for ($i = 0; $i print "";
print "";
print "";
print "";
print "";
print "";
print "";
}
print "
$key
".$orderitems['ORDER_ID'][$i]."".$orderitems['LINE_ITEM_ID'][$i]."".$orderitems['PRODUCT_ID'][$i]."".$orderitems['UNIT_PRICE'][$i]."".$orderitems['QUANTITY'][$i]."
";
} else {
print "Some problem occurred while getting order line items";
$cache->drop('getOrderItems', $order_no);
}
?>

  “清單 7”中的 testCache.php 腳本應(yīng)與 order_no URL 參數(shù)(代表 OE.ORDER 表中存儲的訂單 ID)一起被調(diào)用。例如,要檢索與 ID 為 2408 的訂單相關(guān)的信息,需要在瀏覽器中輸入如下所示的 URL:

http://webserverhost/phpcache/testCache.php?order_no=2408  結(jié)果,瀏覽器將生成以下輸出:
  ORDER #2408

DATE: 29-JUN-99 06.59.31.333617 AM
CUST_ID: 166
TOTAL: 309
ORDER_ID LINE_ITEM_ID PRODUCT_ID UNIT_PRICE QUANTITY
2408 1 2751 61 3
2408 2 2761 26 1
2408 3 2783 10 10

  現(xiàn)在,如果您單擊瀏覽器中的 reload 按鈕,testCache.php 腳本將不會再次調(diào)用 getOrderFields 和 getOrderItems 函數(shù)。相反,它將從本地緩存中讀取它們的結(jié)果。因此,從現(xiàn)在起的 24 小時(因?yàn)?lifeTime 設(shè)置為 86400 秒)以內(nèi),本地緩存即可滿足使用 order_no=2108 的每個 getOrderFields 或 getOrderItems 調(diào)用的需要。但請注意,Cache_Lite_Function 類未提供 API 來測試具有給定參數(shù)的給定函數(shù)是否存在可用緩存。因此,要確定每次使用相同參數(shù)調(diào)用函數(shù)時應(yīng)用程序是實(shí)際上讀取緩存還是仍執(zhí)行該函數(shù)可能有點(diǎn)棘手。例如,在以上示例中,要確保緩存機(jī)制正常工作,您可以臨時更改 connect.php 腳本中指定的連接信息,以便它無法建立數(shù)據(jù)庫連接;比如指定一個錯誤的數(shù)據(jù)庫服務(wù)器主機(jī)名稱,然后再次使用 order_no=2108 運(yùn)行 testCache.php 腳本。如果緩存正常工作,瀏覽器的輸出應(yīng)與先前的一樣。

  此外,您還可以檢查緩存目錄,該目錄作為 cacheDir 選項(xiàng)的值(在該示例中為 /tmp)傳遞給 Cache_Lite_Function 類的構(gòu)造函數(shù)。在該目錄中,您將找到兩個剛創(chuàng)建的緩存文件,這些文件的名稱類似于:cache_7b181b55b55aee36ad5e7bd9d5a091ec_3ad04d3024f4cd54296f75c92a359154。注意,如果您是一位 Windows 用戶,則可能要使用 %SystemDrive%\temp 目錄保存緩存文件。如果是這樣,則必須將 cacheDir 選項(xiàng)設(shè)置為 /temp/。

  驗(yàn)證緩存機(jī)制正常工作后,可以接著創(chuàng)建一個 PHP 來處理從數(shù)據(jù)庫服務(wù)器收到的更改通知?!扒鍐?8”是 dropResult.php 腳本。數(shù)據(jù)庫服務(wù)器將調(diào)用該腳本來響應(yīng) ORDERS 和 ORDER_ITEMS 表的更改。

  清單 8. 處理從數(shù)據(jù)庫服務(wù)器收到的更改通知

復(fù)制代碼 代碼如下:


//File:dropResults.php
require_once 'Cache/Lite/Function.php';
$options = array(
'cacheDir' => '/tmp/'
);
$cache = new Cache_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']);
}
}
?>



  創(chuàng)建 dropResult.php 腳本后,請確保在通知處理程序中指定的 URL(如清單 2 所示)正確。然后,在 SQL*Plus 或類似工具中以 OE/OE 連接,并執(zhí)行 UPDATE 語句,這些語句將影響本部分先前通過 testCache.php 腳本訪問的同一訂單(此處是 ID 為 2408 的訂單):

UPDATE ORDERS SET order_mode = 'direct' WHERE order_id=2408;
UPDATE ORDER_ITEMS SET quantity = 3 WHERE order_id=2408 AND line_item_id=1;
UPDATE ORDER_ITEMS SET quantity = 1 WHERE order_id=2408 AND line_item_id=2;
COMMIT;
  為響應(yīng)以上更新,本文前面介紹的通知處理程序?qū)⒅饌€使用下列 URL 運(yùn)行 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 腳本在從數(shù)據(jù)庫服務(wù)器收到更改通知后并未刷新緩存。它只是刪除了包含過期數(shù)據(jù)的緩存文件。因此,如果現(xiàn)在檢查緩存目錄,則將看到在使用 order_no=2408 運(yùn)行 testCache.php 腳本時創(chuàng)建的緩存文件已經(jīng)消失。這實(shí)際上意味著,testCache.php 在下次請求與 ID 為 2408 的訂單相關(guān)的數(shù)據(jù)時將從后端數(shù)據(jù)庫而非本地緩存中獲取該數(shù)據(jù)。

  您會發(fā)現(xiàn),在應(yīng)用程序請求的結(jié)果集很有可能在應(yīng)用程序使用它之前更改的情況下該方法將很有用。就本文的示例而言,這意味著與特定訂單相關(guān)的數(shù)據(jù)可能在 testCache.php 訪問該訂單之前多次更改。這樣,應(yīng)用程序會因在從數(shù)據(jù)庫服務(wù)器收到更改通知后立即刷新它的緩存而做了大量不必要的工作。

  但如果您希望 dropResult.php 腳本在收到更改通知后立即刷新緩存,則可以在調(diào)用 drop 方法后調(diào)用 Cache_Lite_Function 實(shí)例的 call 方法,并為這兩個調(diào)用指定相同的參數(shù)。在該情形下,還應(yīng)確保包含 getOrderFields.php 和 getOrderItems.php 腳本,以便 dropResults.php 可以調(diào)用 getOrderFields 和 getOrderItems 函數(shù)來刷新緩存?!扒鍐?9”是修改后的 dropResult.php 腳本。

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

復(fù)制代碼 代碼如下:


//File:dropResults.php
require_once 'Cache/Lite/Function.php';
require_once 'getOrderItems.php';
require_once 'getOrderFields.php';
$options = array(
'cacheDir' => '/tmp/',
'lifeTime' => 86400
);
$cache = new Cache_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 表中的數(shù)據(jù)很少更改并且應(yīng)用程序頻繁訪問它,則以上方法可能很有用。

  總結(jié)

  如果 PHP 應(yīng)用程序與 Oracle 數(shù)據(jù)庫 10g 第 2 版交互,則可以利用“數(shù)據(jù)庫更改通知特性”,通過該特性應(yīng)用程序可以接收通知來響應(yīng)對與發(fā)出的請求關(guān)聯(lián)的對象進(jìn)行的 DML 更改。使用該特性,您不必在特定時間段更新應(yīng)用程序中的緩存。相反,僅當(dāng)注冊查詢的結(jié)果集已經(jīng)更改時才執(zhí)行該操作。
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How Do Generators Work in PHP? How Do Generators Work in PHP? Jul 11, 2025 am 03:12 AM

AgeneratorinPHPisamemory-efficientwaytoiterateoverlargedatasetsbyyieldingvaluesoneatatimeinsteadofreturningthemallatonce.1.Generatorsusetheyieldkeywordtoproducevaluesondemand,reducingmemoryusage.2.Theyareusefulforhandlingbigloops,readinglargefiles,or

How to prevent session hijacking in PHP? How to prevent session hijacking in PHP? Jul 11, 2025 am 03:15 AM

To prevent session hijacking in PHP, the following measures need to be taken: 1. Use HTTPS to encrypt the transmission and set session.cookie_secure=1 in php.ini; 2. Set the security cookie attributes, including httponly, secure and samesite; 3. Call session_regenerate_id(true) when the user logs in or permissions change to change to change the SessionID; 4. Limit the Session life cycle, reasonably configure gc_maxlifetime and record the user's activity time; 5. Prohibit exposing the SessionID to the URL, and set session.use_only

How to access a character in a string by index in PHP How to access a character in a string by index in PHP Jul 12, 2025 am 03:15 AM

In PHP, you can use square brackets or curly braces to obtain string specific index characters, but square brackets are recommended; the index starts from 0, and the access outside the range returns a null value and cannot be assigned a value; mb_substr is required to handle multi-byte characters. For example: $str="hello";echo$str[0]; output h; and Chinese characters such as mb_substr($str,1,1) need to obtain the correct result; in actual applications, the length of the string should be checked before looping, dynamic strings need to be verified for validity, and multilingual projects recommend using multi-byte security functions uniformly.

How to URL encode a string in PHP with urlencode How to URL encode a string in PHP with urlencode Jul 11, 2025 am 03:22 AM

The urlencode() function is used to encode strings into URL-safe formats, where non-alphanumeric characters (except -, _, and .) are replaced with a percent sign followed by a two-digit hexadecimal number. For example, spaces are converted to signs, exclamation marks are converted to!, and Chinese characters are converted to their UTF-8 encoding form. When using, only the parameter values ??should be encoded, not the entire URL, to avoid damaging the URL structure. For other parts of the URL, such as path segments, the rawurlencode() function should be used, which converts the space to . When processing array parameters, you can use http_build_query() to automatically encode, or manually call urlencode() on each value to ensure safe transfer of data. just

PHP get the first N characters of a string PHP get the first N characters of a string Jul 11, 2025 am 03:17 AM

You can use substr() or mb_substr() to get the first N characters in PHP. The specific steps are as follows: 1. Use substr($string,0,N) to intercept the first N characters, which is suitable for ASCII characters and is simple and efficient; 2. When processing multi-byte characters (such as Chinese), mb_substr($string,0,N,'UTF-8'), and ensure that mbstring extension is enabled; 3. If the string contains HTML or whitespace characters, you should first use strip_tags() to remove the tags and trim() to clean the spaces, and then intercept them to ensure the results are clean.

PHP get the last N characters of a string PHP get the last N characters of a string Jul 11, 2025 am 03:17 AM

There are two main ways to get the last N characters of a string in PHP: 1. Use the substr() function to intercept through the negative starting position, which is suitable for single-byte characters; 2. Use the mb_substr() function to support multilingual and UTF-8 encoding to avoid truncating non-English characters; 3. Optionally determine whether the string length is sufficient to handle boundary situations; 4. It is not recommended to use strrev() substr() combination method because it is not safe and inefficient for multi-byte characters.

How to set and get session variables in PHP? How to set and get session variables in PHP? Jul 12, 2025 am 03:10 AM

To set and get session variables in PHP, you must first always call session_start() at the top of the script to start the session. 1. When setting session variables, use $_SESSION hyperglobal array to assign values ??to specific keys, such as $_SESSION['username']='john_doe'; it can store strings, numbers, arrays and even objects, but avoid storing too much data to avoid affecting performance. 2. When obtaining session variables, you need to call session_start() first, and then access the $_SESSION array through the key, such as echo$_SESSION['username']; it is recommended to use isset() to check whether the variable exists to avoid errors

How to prevent SQL injection in PHP How to prevent SQL injection in PHP Jul 12, 2025 am 03:02 AM

Key methods to prevent SQL injection in PHP include: 1. Use preprocessing statements (such as PDO or MySQLi) to separate SQL code and data; 2. Turn off simulated preprocessing mode to ensure true preprocessing; 3. Filter and verify user input, such as using is_numeric() and filter_var(); 4. Avoid directly splicing SQL strings and use parameter binding instead; 5. Turn off error display in the production environment and record error logs. These measures comprehensively prevent the risk of SQL injection from mechanisms and details.

See all articles