久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

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

瀏覽:38日期:2024-02-09 13:29:17

眾所周知,緩存數(shù)據(jù)庫查詢的結(jié)果可以顯著縮短腳本執(zhí)行時(shí)間,并最大限度地減少數(shù)據(jù)庫服務(wù)器上的負(fù)載。如果要處理的數(shù)據(jù)基本上是靜態(tài)的,則該技術(shù)將非常有效。這是因?yàn)閷?duì)遠(yuǎn)程數(shù)據(jù)庫的許多數(shù)據(jù)請(qǐng)求最終可以從本地緩存得到滿足,從而不必連接到數(shù)據(jù)庫、執(zhí)行查詢以及獲取結(jié)果。

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

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

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

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

您必須先將 CHANGE NOTIFICATION 系統(tǒng)權(quán)限以及 EXECUTE ON DBMS_CHANGENOTIFICATION 權(quán)限授予 OE 用戶,才能注冊(cè)對(duì) ORDERS 和 ORDER_ITEMS 表的查詢,以便接收通知和響應(yīng)對(duì)這兩個(gè)表所做的 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)建一個(gè)通知處理程序。但首先,您必須創(chuàng)建將由通知處理程序使用的數(shù)據(jù)庫對(duì)象。例如,您可能需要?jiǎng)?chuàng)建一個(gè)或多個(gè)數(shù)據(jù)庫表,以便通知處理程序?qū)⒆?cè)表的更改記錄到其中。在以下示例中,您將創(chuàng)建 nfresults 表來記錄以下信息:更改發(fā)生的日期和時(shí)間、被修改的表的名稱以及一個(gè)消息(說明通知處理程序是否成功地將通知消息發(fā)送給客戶端)。

CONNECT oe/oe;

CREATE TABLE nfresults ( operdate DATE,; tblname VARCHAR2(60),; rslt_msg VARCHAR2(100) ); 在實(shí)際情況中,您可能需要?jiǎng)?chuàng)建更多表來記錄通知事件以及所更改行的行 ID 等信息,但就本文而言,nfresults 表完全可以滿足需要。

使用 UTL_HTTP 向客戶端發(fā)送通知

您可能還要?jiǎng)?chuàng)建一個(gè)或多個(gè) PL/SQL 存儲(chǔ)過程,并從通知處理程序中調(diào)用這些存儲(chǔ)過程,從而實(shí)現(xiàn)一個(gè)更具可維護(hù)性和靈活性的解決方案。例如,您可能要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)將通知消息發(fā)送給客戶端的存儲(chǔ)過程。“清單 1”是 PL/SQL 過程 sendNotification。該過程使用 UTL_HTTPPL 程序包向客戶端應(yīng)用程序發(fā)送更改通知。

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

CREATE OR REPLACE PROCEDURE sendNotification(url IN VARCHAR2,; tblname IN VARCHAR2, order_id IN VARCHAR2) IS reqUTL_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 請(qǐng)求的形式向客戶端發(fā)送通知消息。此 URL 包含 ORDERS 表中已更改行的 order_id。然后,它使用 UTL_HTTP.GET_RESPONSE 獲取客戶端發(fā)出的響應(yīng)信息。實(shí)際上,sendNotification 并不需要處理客戶端返回的整個(gè)響應(yīng),而是只獲取一個(gè)在 RESP 記錄的 reason_phrase 字段中存儲(chǔ)的簡短消息(描述狀態(tài)代碼)。

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

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

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

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

為更改通知?jiǎng)?chuàng)建注冊(cè)

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

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

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 ROWNUM<2; DBMS_CHANGE_NOTIFICATION.REG_END; END; / 本示例針對(duì) ORDERS 表創(chuàng)建了一個(gè)注冊(cè),并將 orders_nf_callback 用作通知處理程序。現(xiàn)在,如果您使用 DML 或 DDL 語句修改 ORDERS 表并提交事務(wù),則將自動(dòng)調(diào)用 orders_nf_callback 函數(shù)。例如,您可能針對(duì) 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.ORDERSNot Found 02-mar-06 04:31:29;OE.ORDERSNot Found 從以上結(jié)果中可以清楚地看到,orders_nf_callback 已經(jīng)正常工作,但未找到客戶端腳本。在該示例中出現(xiàn)這種情況并不意外,這是因?yàn)槟⑽磩?chuàng)建 URL 中指定的 dropResults.php 腳本。有關(guān) dropResults.php 腳本的說明,請(qǐng)參閱本文后面的構(gòu)建客戶端 部分。

將表添加到現(xiàn)有注冊(cè)

前一部分介紹了如何使用更改通知服務(wù)使數(shù)據(jù)庫在注冊(cè)對(duì)象(在以上示例中為 ORDERS 表)發(fā)生更改時(shí)發(fā)出通知。但從性能角度而言,客戶端應(yīng)用程序可能更希望緩存 ORDER_ITEMS 表而非 ORDERS 表本身的查詢結(jié)果集,這是因?yàn)樗诿看卧L問訂單時(shí),不得不從 ORDERS 表中只檢索一行,但同時(shí)必須從 ORDER_ITEMS 表中檢索多個(gè)行。在實(shí)際情況中,訂單可能包含數(shù)十個(gè)甚至數(shù)百個(gè)訂單項(xiàng)。

由于您已經(jīng)對(duì) ORDERS 表注冊(cè)了查詢,因此不必再創(chuàng)建一個(gè)注冊(cè)來注冊(cè)對(duì) ORDER_ITEMS 表的查詢了。相反,您可以使用現(xiàn)有注冊(cè)。為此,您首先需要檢索現(xiàn)有注冊(cè)的 ID。可以執(zhí)行以下查詢來完成此工作:

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

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

DECLARE ord_id NUMBER; BEGIN DBMS_CHANGE_NOTIFICATION.ENABLE_REG(241); SELECT order_id INTO ord_id FROM order_items WHERE ROWNUM < 2; DBMS_CHANGE_NOTIFICATION.REG_END; END; / 完成了!從現(xiàn)在開始,數(shù)據(jù)庫將生成一個(gè)通知來響應(yīng)對(duì) ORDERS 和 ORDER_ITEMS 所做的任何更改,并調(diào)用 orders_nf_callback 過程來處理通知。因此,下一步就是編輯 orders_nf_callback,以便它可以處理因?qū)?ORDER_ITEMS 表執(zhí)行 DML 操作而生成的通知。但在重新創(chuàng)建 orders_nf_callback 過程之前,您需要?jiǎng)?chuàng)建以下將在更新過程中引用的表類型:

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

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; 插入以下代碼:

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 后,您需要測(cè)試它能否正常工作。為此,您可以針對(duì) 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í)際上,這兩個(gè)更新了的行具有相同的 order_id – 即它們屬于同一訂單。此處,我們假設(shè)客戶端應(yīng)用程序?qū)⑹褂靡粋€(gè)語句選擇訂單的所有訂單項(xiàng),因此它并不需要確切知道已經(jīng)更改了某個(gè)訂單的哪些訂單項(xiàng)。相反,客戶端需要知道其中至少修改、刪除或插入了一個(gè)訂單項(xiàng)的訂單 ID。

構(gòu)建客戶端

現(xiàn)在,您已經(jīng)針對(duì) ORDERS 和 ORDER_ITEMS 表創(chuàng)建了注冊(cè),下面我們將了解一下訪問這些表中存儲(chǔ)的訂單及其訂單項(xiàng)的客戶端應(yīng)用程序如何使用更改通知。為此,您可以構(gòu)建一個(gè) PHP 應(yīng)用程序,它將緩存針對(duì)以上表的查詢結(jié)果,并采取相應(yīng)的操作來響應(yīng)有關(guān)對(duì)這些表所做更改的通知(從數(shù)據(jù)庫服務(wù)器中收到這些通知)。一個(gè)簡單的方法是使用 PEAR::Cache_Lite 程序包,它為您提供了一個(gè)可靠的機(jī)制來使緩存數(shù)據(jù)保持最新狀態(tài)。尤其是,您可以使用 Cache_Lite_Function 類(PEAR::Cache_Lite 程序包的一部分),通過該類您可以緩存函數(shù)調(diào)用。

例如,您可以創(chuàng)建一個(gè)函數(shù)來執(zhí)行下列任務(wù):建立數(shù)據(jù)庫連接、針對(duì)該數(shù)據(jù)庫執(zhí)行 select 語句、獲取檢索結(jié)果并最終以數(shù)組形式返回結(jié)果。然后,您可以通過 Cache_Lite_Function 實(shí)例的 call 方法緩存由該函數(shù)返回的結(jié)果數(shù)組,以便可以從本地緩存而不是從后端數(shù)據(jù)庫讀取這些數(shù)組,這樣可以顯著提高應(yīng)用程序的性能。然后,在收到緩存數(shù)據(jù)更改的通知時(shí),您將使用 Cache_Lite_Function 實(shí)例的 drop 方法刪除緩存中的過期數(shù)據(jù)。

回過頭來看看本文的示例,您可能要?jiǎng)?chuàng)建兩個(gè)函數(shù),用于應(yīng)用程序與數(shù)據(jù)庫交互:第一個(gè)函數(shù)將查詢 ORDERS 表并返回具有指定 ID 的訂單,而另一個(gè)函數(shù)將查詢 ORDER_ITEMS 表并返回該訂單的訂單項(xiàng)。“清單 4”顯示了包含 getOrderFields 函數(shù)(該函數(shù)接受訂單 ID 并返回一個(gè)包含所檢索到訂單的某些字段的關(guān)聯(lián)數(shù)組)的 getOrderFields.php 腳本。

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

<?php //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 并返回一個(gè)二維數(shù)組,該數(shù)組包含表示訂單的訂單項(xiàng)的行。

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

<?php //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); } ?> 注意,以上兩個(gè)函數(shù)都需要 connect.php 腳本,該腳本應(yīng)包含返回?cái)?shù)據(jù)庫連接的 GetConnection 函數(shù)。清單 6 就是 connect.php 腳本:

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

<?php //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 緩存

<?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('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 '<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 'Some problem occurred while getting order fields!n'; $cache->drop('getOrderFields', $order_no); }

if (list($nrows, $orderitems) = $cache->call('getOrderItems', $order_no)){ //print '<h3>LINE ITEMS IN ORDER #$order_no</h3>'; print '<table border=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 'Some problem occurred while getting order line items'; $cache->drop('getOrderItems', $order_no); } ?> “清單 7”中的 testCache.php 腳本應(yīng)與 order_no URL 參數(shù)(代表 OE.ORDER 表中存儲(chǔ)的訂單 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 腳本將不會(huì)再次調(diào)用 getOrderFields 和 getOrderItems 函數(shù)。相反,它將從本地緩存中讀取它們的結(jié)果。因此,從現(xiàn)在起的 24 小時(shí)(因?yàn)?lifeTime 設(shè)置為 86400 秒)以內(nèi),本地緩存即可滿足使用 order_no=2108 的每個(gè) getOrderFields 或 getOrderItems 調(diào)用的需要。但請(qǐng)注意,Cache_Lite_Function 類未提供 API 來測(cè)試具有給定參數(shù)的給定函數(shù)是否存在可用緩存。因此,要確定每次使用相同參數(shù)調(diào)用函數(shù)時(shí)應(yīng)用程序是實(shí)際上讀取緩存還是仍執(zhí)行該函數(shù)可能有點(diǎn)棘手。例如,在以上示例中,要確保緩存機(jī)制正常工作,您可以臨時(shí)更改 connect.php 腳本中指定的連接信息,以便它無法建立數(shù)據(jù)庫連接;比如指定一個(gè)錯(cuò)誤的數(shù)據(jù)庫服務(wù)器主機(jī)名稱,然后再次使用 order_no=2108 運(yùn)行 testCache.php 腳本。如果緩存正常工作,瀏覽器的輸出應(yīng)與先前的一樣。

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

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

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

<?php //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 腳本后,請(qǐng)確保在通知處理程序中指定的 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ū)⒅饌€(gè)使用下列 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 腳本時(shí)創(chuàng)建的緩存文件已經(jīng)消失。這實(shí)際上意味著,testCache.php 在下次請(qǐng)求與 ID 為 2408 的訂單相關(guān)的數(shù)據(jù)時(shí)將從后端數(shù)據(jù)庫而非本地緩存中獲取該數(shù)據(jù)。

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

但如果您希望 dropResult.php 腳本在收到更改通知后立即刷新緩存,則可以在調(diào)用 drop 方法后調(diào)用 Cache_Lite_Function 實(shí)例的 call 方法,并為這兩個(gè)調(diào)用指定相同的參數(shù)。在該情形下,還應(yīng)確保包含 getOrderFields.php 和 getOrderItems.php 腳本,以便 dropResults.php 可以調(diào)用 getOrderFields 和 getOrderItems 函數(shù)來刷新緩存。“清單 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 = 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']); } }; ?> 如果存儲(chǔ)在 ORDERS 和 ORDER_ITEMS 表中的數(shù)據(jù)很少更改并且應(yīng)用程序頻繁訪問它,則以上方法可能很有用。

總結(jié)

如果 PHP 應(yīng)用程序與 Oracle 數(shù)據(jù)庫 10g 第 2 版交互,則可以利用“數(shù)據(jù)庫更改通知特性”,通過該特性應(yīng)用程序可以接收通知來響應(yīng)對(duì)與發(fā)出的請(qǐng)求關(guān)聯(lián)的對(duì)象進(jìn)行的 DML 更改。使用該特性,您不必在特定時(shí)間段更新應(yīng)用程序中的緩存。相反,僅當(dāng)注冊(cè)查詢的結(jié)果集已經(jīng)更改時(shí)才執(zhí)行該操作。

標(biāo)簽: PHP
主站蜘蛛池模板: 亚洲成人首页 | 黄色91| 国产日韩免费视频 | 免费欧美视频 | 国产精品久久久久久久免费大片 | 成人三区 | 国产欧美精品一区二区三区 | 三级黄色在线视频 | 色黄视频在线观看 | 国产精品视频999 | 精品国产一区一区二区三亚瑟 | 欧美性v | 国产精品二区一区二区aⅴ污介绍 | 三区免费视频 | 一级a性色生活片毛片 | 久久成人综合 | 亚洲成人免费在线 | 羞视频在线观看 | 中字精品 | 欧洲成人在线观看 | 国产福利91精品一区二区三区 | 一区久久 | 亚洲精品久久久久久一区二区 | 欧美久久久久久久久久伊人 | 成人免毛片 | 极品白嫩少妇无套内谢 | 伊人网伊人 | 欧美久久久久久久久久伊人 | 日韩不卡在线 | 欧美xxxx做受欧美 | 午夜精品导航 | 播放一级黄色片 | 日韩成人三级 | 日韩精品99久久久久中文字幕 | 在线视频一区二区三区 | 日韩成人免费中文字幕 | 中文字幕在线播放一区 | 大伊人久久 | 高清一区二区三区视频 | 日本videos18高清hd下 | 国变精品美女久久久久av爽 |