เป็นที่ทราบกันดีว่าการแคชผลลัพธ์ของการสืบค้นฐานข้อมูลสามารถลดเวลาดำเนินการสคริปต์ได้อย่างมาก และลดภาระบนเซิร์ฟเวอร์ฐานข้อมูลให้เหลือน้อยที่สุด เทคนิคนี้ใช้ได้ผลดีมากหากข้อมูลที่คุณกำลังประมวลผลเป็นแบบคงที่ เนื่องจากคำขอข้อมูลจำนวนมากไปยังฐานข้อมูลระยะไกลสามารถตอบสนองได้จากแคชในเครื่องในที่สุด ซึ่งช่วยลดความจำเป็นในการเชื่อมต่อกับฐานข้อมูล ดำเนินการค้นหา และรับผลลัพธ์
แต่การแคชชุดผลลัพธ์ฐานข้อมูลมักเป็นความคิดที่ดี เมื่อฐานข้อมูลที่คุณใช้อยู่บนคอมพิวเตอร์เครื่องอื่นที่ไม่ใช่เว็บเซิร์ฟเวอร์ อย่างไรก็ตาม การกำหนดกลยุทธ์การแคชที่ดีที่สุดสำหรับสถานการณ์ของคุณอาจเป็นเรื่องยาก ตัวอย่างเช่น สำหรับแอปพลิเคชันที่มีความสำคัญต่อการใช้ชุดผลลัพธ์ฐานข้อมูลล่าสุด วิธีการแคชที่กระตุ้นตามเวลา (โดยทั่วไปใช้โดยระบบแคชที่ถือว่าแคชถูกสร้างใหม่ทุกครั้งที่ถึงการประทับเวลาหมดอายุ) อาจไม่ใช่วิธีแก้ปัญหาที่น่าพอใจ . ในกรณีนี้ คุณต้องมีกลไกที่จะแจ้งเตือนแอปพลิเคชันเมื่อใดก็ตามที่ข้อมูลฐานข้อมูลที่แอปพลิเคชันจำเป็นต้องแคชเปลี่ยนแปลง เพื่อให้แอปพลิเคชันสามารถเก็บข้อมูลที่แคชไว้หมดอายุให้สอดคล้องกับฐานข้อมูล ในกรณีนี้การใช้ "การแจ้งเตือนการเปลี่ยนแปลงฐานข้อมูล" จะสะดวกมาก
การเริ่มต้นใช้งานการแจ้งเตือนการเปลี่ยนแปลงฐานข้อมูล
การใช้คุณลักษณะการแจ้งเตือนการเปลี่ยนแปลงฐานข้อมูลนั้นง่ายมาก: สร้างตัวจัดการการแจ้งเตือนที่ดำเนินการสำหรับการแจ้งเตือน – ขั้นตอนการจัดเก็บ PL/SQL หรือฟังก์ชันการเรียกกลับ OCI ของไคลเอ็นต์ จากนั้น ให้ลงทะเบียนแบบสอบถามกับออบเจ็กต์ฐานข้อมูลที่คุณต้องการรับการแจ้งเตือนการเปลี่ยนแปลง เพื่อให้ตัวจัดการการแจ้งเตือนถูกเรียกเมื่อใดก็ตามที่ธุรกรรมเปลี่ยนแปลงออบเจ็กต์ใดๆ ภายในและยอมรับ โดยทั่วไป ตัวจัดการการแจ้งเตือนจะส่งชื่อของตารางที่ได้รับการแก้ไข ประเภทของการเปลี่ยนแปลงที่ทำ และ ID แถวของแถวที่เปลี่ยนแปลง (ไม่บังคับ) ไปยังผู้ฟังไคลเอ็นต์ เพื่อให้แอปพลิเคชันไคลเอนต์สามารถดำเนินการที่เหมาะสมในการจัดการกับการตอบสนอง
เพื่อให้เข้าใจถึงวิธีการทำงานของคุณลักษณะการแจ้งเตือนการเปลี่ยนแปลงฐานข้อมูล ให้พิจารณาตัวอย่างต่อไปนี้ สมมติว่าแอปพลิเคชัน PHP ของคุณเข้าถึงคำสั่งซื้อที่จัดเก็บไว้ในตาราง OE.ORDERS และรายการสั่งซื้อที่จัดเก็บไว้ใน OE.ORDER_ITEMS เนื่องจากข้อมูลเกี่ยวกับคำสั่งซื้อที่วางไว้ไม่ค่อยมีการเปลี่ยนแปลง คุณอาจต้องการให้แอปพลิเคชันของคุณแคชชุดผลลัพธ์ของการสืบค้นกับทั้งตาราง ORDERS และ ORDER_ITEMS เพื่อหลีกเลี่ยงการเข้าถึงข้อมูลเก่า คุณสามารถใช้การแจ้งเตือนการเปลี่ยนแปลงฐานข้อมูล ซึ่งช่วยให้แอปพลิเคชันของคุณสามารถแจ้งเตือนการเปลี่ยนแปลงข้อมูลที่จัดเก็บไว้ในสองตารางด้านบนได้อย่างง่ายดาย
คุณต้องให้สิทธิ์ระบบการแจ้งเตือนการเปลี่ยนแปลงและสิทธิ์ดำเนินการบน DBMS_CHANGENOTIFICATION แก่ผู้ใช้ OE ก่อนที่คุณจะสามารถลงทะเบียนแบบสอบถามสำหรับตาราง ORDERS และ ORDER_ITEMS เพื่อรับการแจ้งเตือนและตอบสนองต่อการเปลี่ยนแปลง DML หรือ DDL ในตารางเหล่านี้ เมื่อต้องการทำเช่นนี้ ให้รันคำสั่งต่อไปนี้จากเครื่องมือบรรทัดคำสั่ง SQL เช่น SQL*Plus
เชื่อมต่อ/เป็น SYSDBA;
แจ้งการเปลี่ยนแปลงให้สิทธิ์แก่ oe;
ให้สิทธิ์ดำเนินการกับ DBMS_CHANGE_NOTIFICATION ถึง oe;
ตรวจสอบให้แน่ใจว่าพารามิเตอร์ init.ora job_queue_processes ถูกตั้งค่าเป็นค่าที่ไม่ใช่ศูนย์เพื่อรับการแจ้งเตือน PL/SQL หรือคุณสามารถใช้คำสั่ง ALTER SYSTEM ต่อไปนี้:
ALTER SYSTEM SET "job_queue_processes"=2; จากนั้น หลังจากเชื่อมต่อเป็น OE/OE แล้ว คุณสามารถสร้างตัวจัดการการแจ้งเตือนได้ แต่ก่อนอื่น คุณต้องสร้างวัตถุฐานข้อมูลที่จะใช้โดยตัวจัดการการแจ้งเตือน ตัวอย่างเช่น คุณอาจต้องการสร้างตารางฐานข้อมูลอย่างน้อยหนึ่งตารางที่ตัวจัดการการแจ้งเตือนบันทึกการเปลี่ยนแปลงรีจิสทรี ในตัวอย่างต่อไปนี้ คุณสร้างตาราง nfresults เพื่อบันทึกวันที่และเวลาที่การเปลี่ยนแปลงเกิดขึ้น ชื่อของตารางที่ได้รับการแก้ไข และข้อความที่ระบุว่าตัวจัดการการแจ้งเตือนส่งข้อความแจ้งเตือนไปยังไคลเอนต์สำเร็จหรือไม่
เชื่อมต่อ oe/oe;
สร้างตาราง nfresults (
ดำเนินการวันที่,
ชื่อ tblVARCHAR2(60),
rslt_msg VARCHAR2(100)
-
ในสถานการณ์จริง คุณอาจต้องสร้างตารางเพิ่มเติมเพื่อบันทึกข้อมูล เช่น เหตุการณ์การแจ้งเตือนและรหัสแถวของแถวที่เปลี่ยนแปลง แต่สำหรับวัตถุประสงค์ของบทความนี้ ตาราง nfresults ก็เพียงพอแล้ว
การใช้ UTL_HTTP เพื่อส่งการแจ้งเตือนไปยังไคลเอนต์
คุณยังอาจสร้างขั้นตอนการจัดเก็บ PL/SQL อย่างน้อยหนึ่งขั้นตอน และเรียกขั้นตอนการจัดเก็บเหล่านี้จากตัวจัดการการแจ้งเตือน ซึ่งจะทำให้ได้โซลูชันที่สามารถบำรุงรักษาและยืดหยุ่นได้มากขึ้น ตัวอย่างเช่น คุณอาจต้องการสร้างขั้นตอนการจัดเก็บที่ใช้การส่งข้อความแจ้งเตือนไปยังไคลเอนต์ "รายการ 1" เป็นขั้นตอน PL/SQL sendNotification กระบวนการนี้ใช้แพ็คเกจ UTL_HTTPPL เพื่อส่งการแจ้งเตือนการเปลี่ยนแปลงไปยังแอปพลิเคชันไคลเอนต์
รายการ 1. ส่งการแจ้งเตือนไปยังไคลเอนต์โดยใช้ UTL_HTTPCREATE
หรือแทนที่ขั้นตอน sendNotification(url IN VARCHAR2,
tblname ใน VARCHAR2, order_id ใน VARCHAR2) คือ
ต้องการ UTL_HTTP.REQ;
ตอบ UTL_HTTP.RESP;
err_msg VARCHAR2(100);
tbl วาร์ชาร์(60);
เริ่ม
tbl:=SUBSTR(tblname, INSTR(tblname, '.', 1, 1)+1, 60);
เริ่ม
ต้องการ := UTL_HTTP.BEGIN_REQUEST(url||order_id||'&'||'table='||tbl);
ตอบ := UTL_HTTP.GET_RESPONSE(req);
แทรกลงในค่า nfresults (SYSDATE, tblname, resp.reason_phrase);
UTL_HTTP.END_RESPONSE(ตอบ);
ข้อยกเว้นเมื่อคนอื่นแล้ว
err_msg := SUBSTR(SQLERRM, 1, 100);
แทรกลงในค่า nfresults (SYSDATE, tblname, err_msg);
จบ;
ให้สัญญา;
จบ;
-
ดังที่แสดงใน "รายการ 1" sendNotification ส่งข้อความแจ้งเตือนไปยังไคลเอนต์ในรูปแบบของคำขอ HTTP ที่ออกโดยฟังก์ชัน UTL_HTTP.BEGIN_REQUEST URL นี้มี order_id ของแถวที่เปลี่ยนแปลงในตาราง ORDERS จากนั้นใช้ UTL_HTTP.GET_RESPONSE เพื่อรับข้อมูลตอบกลับที่ส่งมาจากไคลเอนต์ ที่จริงแล้ว sendNotification ไม่จำเป็นต้องประมวลผลการตอบสนองทั้งหมดที่ไคลเอ็นต์ส่งคืน แต่จะได้รับเพียงข้อความสั้น ๆ (อธิบายรหัสสถานะ) ที่จัดเก็บไว้ในฟิลด์ Reason_phrase ของบันทึก RESP
การสร้างตัวจัดการการแจ้งเตือน
ตอนนี้คุณสามารถสร้างตัวจัดการการแจ้งเตือนที่จะส่งการแจ้งเตือนการเปลี่ยนแปลงไปยังไคลเอนต์ด้วยความช่วยเหลือของขั้นตอน sendNotification ที่อธิบายไว้ข้างต้น ลองมาดูที่ขั้นตอน PL/SQL orders_nf_callback ใน "รายการ 2"
รายการ 2 ตัวจัดการการแจ้งเตือนที่จัดการการแจ้งเตือนการเปลี่ยนแปลงในตาราง OE.ORDERS
สร้างหรือแทนที่กระบวนการ orders_nf_callback (ntfnds ใน SYS.CHNF$_DESC) IS
ชื่อไฟล์ VARCHAR2(60);
ตารางตัวเลข NUMBER;
event_type NUMBER;
row_id VARCHAR2(20);
จำนวน NUMBER;
ord_id VARCHAR2(12);
url VARCHAR2(256) := 'http://webserverhost/phpcache/dropResults.php?order_no=';
เริ่ม
event_type := ntfnds.event_type;
ตัวเลข := ntfnds.numtables;
ถ้า (event_type = DBMS_CHANGE_NOTIFICATION.EVENT_OBJCHANGE) แล้ว
สำหรับฉันใน 1..numtables LOOP
tblname := ntfnds.table_desc_array(i).table_name;
ถ้า (bitand(ntfnds.table_desc_array(i).opflags,
DBMS_CHANGE_NOTIFICATION.ALL_ROWS) = 0) จากนั้น
numrows := ntfnds.table_desc_array(i).numrows;
อื่น
จำนวนแถว :=0;
สิ้นสุดถ้า;
ถ้า (tblname = 'OE.ORDERS') แล้ว
สำหรับ j ใน 1..จำนวน LOOP
row_id := ntfnds.table_desc_array(i).row_desc_array(j).row_id;
เลือก order_id ลงใน ord_id จากคำสั่งซื้อ โดยที่ rowid = row_id;
sendNotification(url, tblname, ord_id);
สิ้นสุดลูป;
สิ้นสุดถ้า;
สิ้นสุดลูป;
สิ้นสุดถ้า;
ให้สัญญา;
จบ;
-
ดังที่แสดงใน "รายการ 2" ตัวจัดการการแจ้งเตือนนี้รับวัตถุ SYS.CHNF$_DESC เป็นพารามิเตอร์ จากนั้นใช้คุณสมบัติเพื่อรับรายละเอียดของการเปลี่ยนแปลง ในตัวอย่างนี้ ตัวจัดการการแจ้งเตือนนี้จะจัดการเฉพาะการแจ้งเตือนที่โพสต์โดยฐานข้อมูลเพื่อตอบสนองต่อการเปลี่ยนแปลง DML หรือ DDL กับอ็อบเจ็กต์ที่ลงทะเบียน (นั่นคือ เฉพาะในกรณีที่ประเภทการแจ้งเตือนเป็น EVENT_OBJCHANGE) และละเว้นข้อมูลเกี่ยวกับเหตุการณ์ฐานข้อมูลอื่น ๆ เช่นการเริ่มต้นอินสแตนซ์หรือ การปิดระบบอินสแตนซ์) การแจ้งเตือน ตั้งแต่เวอร์ชันข้างต้น ตัวจัดการสามารถจัดการการแจ้งเตือนการเปลี่ยนแปลงที่ออกสำหรับแต่ละแถวที่ได้รับผลกระทบในตาราง OE.ORDERS ต่อมาในบทความนี้ ในส่วน "การเพิ่มตารางในการลงทะเบียนที่มีอยู่" คุณจะเพิ่มโค้ดสองสามบรรทัดลงในตัวจัดการเพื่อให้สามารถจัดการการแจ้งเตือนสำหรับแถวที่ปรับเปลี่ยนในตาราง OE.ORDER_ITEMS
สร้างการลงทะเบียนสำหรับการแจ้งเตือนการเปลี่ยนแปลง
หลังจากที่คุณสร้างตัวจัดการการแจ้งเตือน คุณต้องสร้างการลงทะเบียนแบบสอบถามสำหรับมัน สำหรับตัวอย่างนี้ คุณต้องดำเนินการค้นหาในตาราง OE.ORDER ในระหว่างขั้นตอนการลงทะเบียน และระบุ orders_nf_callback เป็นตัวจัดการการแจ้งเตือน คุณต้องระบุตัวเลือก QOS_ROWIDS ในแพ็คเกจ DBMS_CHANGE_NOTIFICATION เพื่อเปิดใช้งานรายละเอียดระดับ ROWID ในข้อความแจ้งเตือน "รายการ 3" คือบล็อก PL/SQL ที่สร้างการลงทะเบียนแบบสอบถามสำหรับตัวจัดการการแจ้งเตือน orders_nf_callback
รายการ 3 สร้างการลงทะเบียนแบบสอบถามDECLARE
สำหรับตัวจัดการการแจ้งเตือน
REGDS SYS.CHNF$_REG_INFO;
หมายเลขทะเบียน;
ord_id NUMBER;
qosflags NUMBER;
เริ่ม
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 เข้าสู่ ord_id จากคำสั่งซื้อโดยที่ ROWNUM<2;
DBMS_CHANGE_NOTIFICATION.REG_END;
จบ;
-
ตัวอย่างนี้สร้างการลงทะเบียนกับตาราง ORDERS และใช้ orders_nf_callback เป็นตัวจัดการการแจ้งเตือน ในตอนนี้ หากคุณใช้คำสั่ง DML หรือ DDL เพื่อแก้ไขตาราง ORDERS และยอมรับธุรกรรม ฟังก์ชัน orders_nf_callback จะถูกเรียกโดยอัตโนมัติ ตัวอย่างเช่น คุณอาจดำเนินการคำสั่ง UPDATE ต่อไปนี้กับตาราง ORDERS และยอมรับธุรกรรม:
UPDATE ORDERS SET order_mode = 'direct' WHERE order_id=2421;
อัปเดตชุดคำสั่งซื้อ order_mode = 'โดยตรง' โดยที่ order_id=2422;
ให้สัญญา;
เพื่อให้แน่ใจว่าฐานข้อมูลโพสต์การแจ้งเตือนเพื่อตอบสนองต่อธุรกรรมข้างต้น คุณสามารถตรวจสอบตาราง nfresults:
SELECT TO_CHAR(operdate, 'dd-mon-yy hh:mi:ss') operdate,
tblname, rslt_msg จาก nfresults;
ผลลัพธ์ควรมีลักษณะดังนี้:
OPERDATE TBLNAME RSLT_MSG
-
02-มี.ค.-06 04:31:28 ไม่พบ OE.ORDERS
02-มี.ค.-06 04:31:29 ไม่พบ OE.ORDERS
จากผลลัพธ์ข้างต้นเป็นที่ชัดเจนว่า orders_nf_callback ใช้งานได้แล้ว แต่ไม่พบสคริปต์ไคลเอ็นต์ นี่ไม่ใช่เรื่องที่ไม่คาดคิดในตัวอย่างนี้ เนื่องจากคุณไม่ได้สร้างสคริปต์ dropResults.php ที่ระบุใน URL สำหรับคำแนะนำเกี่ยวกับสคริปต์ dropResults.php โปรดดูส่วนการสร้างลูกค้าในบทความนี้
การเพิ่มตารางในการลงทะเบียนที่มีอยู่
ส่วนก่อนหน้านี้แสดงวิธีการใช้บริการการแจ้งเตือนการเปลี่ยนแปลงเพื่อให้ฐานข้อมูลแจ้งให้คุณทราบเมื่อออบเจ็กต์การลงทะเบียน (ในตัวอย่างข้างต้น ตารางคำสั่งซื้อ) มีการเปลี่ยนแปลง แต่จากมุมมองของประสิทธิภาพ แอปพลิเคชันไคลเอ็นต์อาจต้องการแคชชุดผลลัพธ์แบบสอบถามของตาราง ORDER_ITEMS แทนที่จะเป็นตาราง ORDERS เนื่องจากจะต้องดึงข้อมูลเพียงหนึ่งแถวจากตาราง ORDERS ในแต่ละครั้งที่มีการเข้าถึงคำสั่งซื้อ แต่ที่ ในเวลาเดียวกัน ต้องดึงข้อมูลหลายแถวจากตาราง ORDER_ITEMS ในความเป็นจริง คำสั่งซื้ออาจมีรายการสินค้าหลายสิบหรือหลายร้อยรายการ
เนื่องจากคุณได้ลงทะเบียนการสืบค้นกับตาราง ORDERS แล้ว คุณจึงไม่จำเป็นต้องสร้างการลงทะเบียนเพื่อลงทะเบียนการสืบค้นกับตาราง ORDER_ITEMS คุณสามารถใช้การลงทะเบียนที่มีอยู่แทนได้ ในการดำเนินการนี้ คุณต้องดึงข้อมูล ID ของการลงทะเบียนที่มีอยู่ก่อน คุณสามารถดำเนินการค้นหาต่อไปนี้เพื่อทำสิ่งนี้:
SELECT regid, table_name FROM user_change_notification_regs; ผลลัพธ์อาจมีลักษณะดังนี้:
REGID TABLE_NAME
-
241 OE. คำสั่งซื้อ
หลังจากได้รับ ID การลงทะเบียน คุณสามารถเพิ่มออบเจ็กต์ใหม่ให้กับการลงทะเบียนได้โดยใช้ฟังก์ชัน DBMS_CHANGE_NOTIFICATION.ENABLE_REG ดังนี้:
DECLARE
ord_id NUMBER;
เริ่ม
DBMS_CHANGE_NOTIFICATION.ENABLE_REG(241);
เลือก order_id ลงใน ord_id จาก order_items โดยที่ ROWNUM < 2;
DBMS_CHANGE_NOTIFICATION.REG_END;
จบ;
-
เสร็จแล้ว! จากนี้ไป ฐานข้อมูลจะสร้างการแจ้งเตือนเพื่อตอบสนองต่อการเปลี่ยนแปลงใดๆ ที่เกิดขึ้นกับ ORDERS และ ORDER_ITEMS และเรียกใช้ขั้นตอน orders_nf_callback เพื่อจัดการการแจ้งเตือน ดังนั้น ขั้นตอนต่อไปคือการแก้ไข orders_nf_callback เพื่อให้สามารถจัดการการแจ้งเตือนที่สร้างโดยการดำเนินการ DML บนตาราง ORDER_ITEMS แต่ก่อนที่จะสร้างขั้นตอน orders_nf_callback อีกครั้ง คุณต้องสร้างประเภทตารางต่อไปนี้ซึ่งจะถูกอ้างอิงในระหว่างกระบวนการอัพเดต:
CREATE TYPE rdesc_tab AS TABLE OF SYS.CHNF$_RDESC; จากนั้น กลับสู่รายการ 2 หลังจากบรรทัดต่อไปนี้ของ รหัส:
IF (tblname = 'OE.ORDERS') แล้ว
สำหรับ j ใน 1..จำนวน LOOP
row_id := ntfnds.table_desc_array(i).row_desc_array(j).row_id;
เลือก order_id ลงใน ord_id จากคำสั่งซื้อ โดยที่ rowid = row_id;
sendNotification(url, tblname, ord_id);
สิ้นสุดลูป;
สิ้นสุดถ้า;
ใส่รหัสต่อไปนี้:
IF (tblname = 'OE.ORDER_ITEMS') จากนั้น
สำหรับการรับ IN (SELECT DISTINCT(o.order_id) o_id FROM
ตาราง(นักแสดง(ntfnds.table_desc_array(i).row_desc_array AS rdesc_tab)) t,
คำสั่งซื้อ o, order_items d โดยที่ t.row_id = d.rowid และ d.order_id=o.order_id)
วนซ้ำ
sendNotification(url, tblname, rec.o_id);
สิ้นสุดลูป;
สิ้นสุดถ้า;
หลังจากสร้าง orders_nf_callback ใหม่แล้ว คุณต้องทดสอบว่าทำงานได้อย่างถูกต้องหรือไม่ เมื่อต้องการทำเช่นนี้ คุณสามารถดำเนินการคำสั่ง UPDATE ต่อไปนี้กับตาราง ORDER_ITEMS และยอมรับธุรกรรม:
อัปเดต ORDER_ITEMS SET ปริมาณ = 160 WHERE order_id=2421 AND line_item_id=1;
อัปเดตจำนวน ORDER_ITEMS SET = 160 โดยที่ order_id=2421 และ line_item_id=2;
ให้สัญญา;
จากนั้น ตรวจสอบตาราง nfresults ดังนี้:
SELECT TO_CHAR(operdate, 'dd-mon-yy hh:mi:ss') operdate,
rslt_msg จาก nfresults โดยที่ tblname = 'OE.ORDER_ITEMS'; ผลลัพธ์อาจมีลักษณะดังนี้:
OPERDATE RSLT_MSG
-
03 มี.ค. 06 12:32:27 ไม่พบ
คุณอาจสงสัยว่าเหตุใดจึงมีการแทรกเพียงแถวเดียวในตาราง nfresults เพราะท้ายที่สุดแล้ว คุณได้อัปเดตสองแถวในตาราง ORDER_ITEMS ที่จริงแล้ว ทั้งสองแถวที่อัปเดตมี order_id เหมือนกัน กล่าวคือ อยู่ในลำดับเดียวกัน ในที่นี้ เราถือว่าแอปพลิเคชันไคลเอนต์จะใช้คำสั่งเดียวในการเลือกรายการบรรทัดทั้งหมดของคำสั่งซื้อ ดังนั้นจึงไม่จำเป็นต้องทราบแน่ชัดว่ารายการบรรทัดใดในคำสั่งซื้อที่มีการเปลี่ยนแปลง แต่ลูกค้าจำเป็นต้องทราบรหัสคำสั่งซื้อที่มีการแก้ไข ลบ หรือแทรกรายการโฆษณาอย่างน้อยหนึ่งรายการ
การสร้างไคลเอ็นต์
เมื่อคุณได้สร้างการลงทะเบียนสำหรับตาราง ORDERS และ ORDER_ITEMS แล้ว ลองมาดูกันว่าแอปพลิเคชันไคลเอ็นต์ที่เข้าถึงคำสั่งซื้อและรายการบรรทัดที่จัดเก็บไว้ในตารางเหล่านี้ใช้การแจ้งเตือนการเปลี่ยนแปลงอย่างไร ในการดำเนินการนี้ คุณสามารถสร้างแอปพลิเคชัน PHP ที่จะแคชผลลัพธ์ของการสืบค้นกับตารางด้านบน และดำเนินการตามความเหมาะสมเพื่อตอบสนองต่อการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงในตารางเหล่านี้ (ซึ่งได้รับจากเซิร์ฟเวอร์ฐานข้อมูล) วิธีง่ายๆ คือการใช้แพ็คเกจ PEAR::Cache_Lite ซึ่งมีกลไกที่เชื่อถือได้ในการอัปเดตข้อมูลแคชให้ทันสมัยอยู่เสมอ โดยเฉพาะอย่างยิ่ง คุณสามารถใช้คลาส Cache_Lite_Function (ส่วนหนึ่งของแพ็คเกจ PEAR::Cache_Lite) ซึ่งช่วยให้คุณแคชการเรียกใช้ฟังก์ชันได้
ตัวอย่างเช่น คุณสามารถสร้างฟังก์ชันที่ดำเนินงานต่อไปนี้: สร้างการเชื่อมต่อฐานข้อมูล ดำเนินการคำสั่ง Select กับฐานข้อมูล รับผลการค้นหา และสุดท้ายก็ส่งคืนผลลัพธ์เป็นอาร์เรย์ จากนั้น คุณสามารถแคชอาร์เรย์ผลลัพธ์ที่ส่งคืนโดยฟังก์ชันผ่านวิธีการเรียกของอินสแตนซ์ Cache_Lite_Function เพื่อให้สามารถอ่านจากแคชในเครื่องแทนที่จะอ่านจากฐานข้อมูลส่วนหลัง ซึ่งสามารถปรับปรุงประสิทธิภาพของแอปพลิเคชันของคุณได้อย่างมาก จากนั้น เมื่อคุณได้รับแจ้งถึงการเปลี่ยนแปลงข้อมูลที่แคช คุณจะใช้วิธีการดรอปของอินสแตนซ์ Cache_Lite_Function เพื่อลบข้อมูลที่หมดอายุในแคช
กลับไปที่ตัวอย่างในบทความนี้ คุณอาจต้องการสร้างสองฟังก์ชันสำหรับแอปพลิเคชันของคุณเพื่อโต้ตอบกับฐานข้อมูล: ฟังก์ชันแรกจะสืบค้นตาราง ORDERS และส่งกลับคำสั่งซื้อด้วย ID ที่ระบุ ในขณะที่ฟังก์ชันอื่นจะสืบค้น ORDER_ITEMS ตาราง และ return ส่งคืนรายการบรรทัดสำหรับคำสั่งซื้อนี้ "รายการ 4" แสดงสคริปต์ getOrderFields.php ที่มีฟังก์ชัน getOrderFields ซึ่งยอมรับรหัสคำสั่งซื้อและส่งกลับอาร์เรย์ที่เชื่อมโยงซึ่งมีบางฟิลด์ของคำสั่งซื้อที่ดึงมา
รายการ 4. รับฟิลด์ของลำดับที่ระบุ
<?php
//ไฟล์:getOrderFields.php
need_once 'connect.php';
ฟังก์ชั่น getOrderFields($order_no) {
ถ้า (!$rsConnection = GetConnection()){
กลับเท็จ;
-
$strSQL = "เลือก TO_CHAR(ORDER_DATE) ORDER_DATE, ลูกค้า_ID,
ORDER_TOTAL จากคำสั่งซื้อที่ order_id =:order_no";
$rsStatement = oci_parse($rsConnection,$strSQL);
oci_bind_by_name($rsStatement, ":order_no", $order_no, 12);
ถ้า (!oci_execute($rsStatement)) {
$err = oci_error();
พิมพ์ $err['ข้อความ'];
trigger_error('แบบสอบถามล้มเหลว:' . $err['ข้อความ']);
กลับเท็จ;
-
$results = oci_fetch_assoc($rsStatement);
ส่งกลับผลลัพธ์ $;
-
?
"Listing 5" คือสคริปต์ getOrderItems.php สคริปต์ประกอบด้วยฟังก์ชัน getOrderItems ซึ่งยอมรับรหัสคำสั่งซื้อและส่งกลับอาร์เรย์สองมิติที่มีแถวที่แสดงรายการโฆษณาของคำสั่งซื้อ
รายการ 5. รับรายการบรรทัดของคำสั่งซื้อที่ระบุ
<?php
//ไฟล์:getOrderItems.php
need_once 'connect.php';
ฟังก์ชั่น getOrderItems($order_no) {
ถ้า (!$rsConnection = GetConnection()){
กลับเท็จ;
-
$strSQL = "เลือก * จาก ORDER_ITEMS โดยที่
order_id =:order_no เรียงตาม line_item_id";
$rsStatement = oci_parse($rsConnection,$strSQL);
oci_bind_by_name($rsStatement, ":order_no", $order_no, 12);
ถ้า (!oci_execute($rsStatement)) {
$err = oci_error();
trigger_error('แบบสอบถามล้มเหลว:' . $err['ข้อความ']);
กลับเท็จ;
-
$nrows = oci_fetch_all($rsStatement, $ผลลัพธ์);
กลับอาร์เรย์ ($nrows, $ผลลัพธ์);
-
?
โปรดทราบว่าทั้งสองฟังก์ชันข้างต้นจำเป็นต้องมีสคริปต์ Connect.php ซึ่งควรมีฟังก์ชัน GetConnection ที่ส่งคืนการเชื่อมต่อฐานข้อมูล รายการ 6 คือสคริปต์ Connect.php:
รายการ 6. รับการเชื่อมต่อฐานข้อมูล
<?php
//ไฟล์:connect.php
ฟังก์ชั่น GetConnection() {
$dbHost = "dbserverhost";
$dbHostPort="1521";
$dbServiceName = "orclR2";
$usr = "oe";
$pswd = "อี";
$dbConnStr = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$dbHost")
(PORT=".$dbHostPort."))(CONNECT_DATA=(SERVICE_NAME=".$dbServiceName.")))";
ถ้า(!$dbConn = oci_connect($usr,$pswd,$dbConnStr)) {
$err = oci_error();
trigger_error('ไม่สามารถเชื่อมต่อ' .$err['ข้อความ']);
กลับเท็จ;
-
ส่งคืน $dbConn;
-
?
ตอนนี้คุณได้สร้างฟังก์ชันทั้งหมดที่จำเป็นในการสื่อสารกับฐานข้อมูลแล้ว มาดูกันว่าคลาส Cache_Lite_Function ทำงานอย่างไร รายการ 7 คือสคริปต์ testCache.php ที่ใช้คลาส Cache_Lite_Function เพื่อแคชผลลัพธ์ของฟังก์ชันข้างต้น
<?php
โดยใช้ PEAR::Cache_Lite
//ไฟล์:testCache.php
need_once 'getOrderItems.php';
need_once 'getOrderFields.php';
need_once 'แคช/Lite/Function.php';
$options = array(
'cacheDir' => '/tmp/',
'อายุการใช้งาน' => 86400
);
ถ้า (!isset($_GET['order_no'])) {
die('จำเป็นต้องมีพารามิเตอร์ order_no');
}
$order_no=$_GET['order_no'];
$cache = Cache_Lite_Function ใหม่($options);
ถ้า ($orderfields = $cache->call('getOrderFields', $order_no)){
พิมพ์ "<h3>ORDER #$order_no</h3">n";
พิมพ์ "<ตาราง>";
print "<tr><<td">DATE:</td><td><".$orderfields['ORDER_DATE']"</td><</tr>";
พิมพ์ "<tr><<td">CUST_ID:</td><td><".$orderfields['CUSTOMER_ID']"</td"></tr><";
print "<tr><<td">TOTAL:</td><td><".$orderfields['ORDER_TOTAL']"</td"></tr">";
พิมพ์ "</table>";
} อื่น {
print "เกิดปัญหาบางอย่างขณะรับฟิลด์คำสั่งซื้อ!n";
$cache->drop('getOrderFields', $order_no);
}
ถ้า (รายการ($nrows, $orderitems) = $cache->call('getOrderItems', $order_no)){
//พิมพ์ "<h3>รายการบรรทัดในคำสั่งซื้อ #$order_no</h3><";
พิมพ์ "<เส้นขอบตาราง=1>";
พิมพ์ "<tr>n";
ในขณะที่ (รายการ($key, $value) = แต่ละรายการ($รายการสั่งซื้อ)) {
พิมพ์ "<th><$key</th>n";
-
พิมพ์ "</tr>n";
สำหรับ ($i = 0; $i < $nrows; $i++) {
พิมพ์ "<tr>";
พิมพ์ "<td>".$orderitems['ORDER_ID'][$i]"</td><";
พิมพ์ "<td><".$orderitems['LINE_ITEM_ID'][$i]"</td><";
พิมพ์ "<td><".$orderitems['PRODUCT_ID'][$i]"</td><";
พิมพ์ "<td><".$orderitems['UNIT_PRICE'][$i]"</td><";
พิมพ์ "<td><".$orderitems['QUANTITY'][$i]"</td><";
พิมพ์ "</tr>";
-
พิมพ์ "</table>";
} อื่น {
พิมพ์ "เกิดปัญหาบางอย่างขณะรับรายการสั่งซื้อ";
$cache->drop('getOrderItems', $order_no);
-
?
สคริปต์ testCache.php ใน "Listing 7" ควรถูกเรียกด้วยพารามิเตอร์ order_no URL (แสดงถึง ID คำสั่งซื้อที่จัดเก็บไว้ในตาราง OE.ORDER) ตัวอย่างเช่น หากต้องการดึงข้อมูลที่เกี่ยวข้องกับคำสั่งซื้อด้วย ID 2408 คุณจะต้องป้อน URL ต่อไปนี้ลงในเบราว์เซอร์ของคุณ:
http://webserverhost/phpcache/testCache.php?order_no=2408 ด้วยเหตุนี้ เบราว์เซอร์จะสร้างผลลัพธ์ต่อไปนี้ :
สั่งซื้อ #2408
วันที่ 29 มิ.ย. 2542 06.59.31.333617 น.
CUST_ID: 166
ทั้งหมด: 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ตอน
นี้ หากคุณคลิกปุ่มโหลดซ้ำในเบราว์เซอร์ สคริปต์ testCache.php จะไม่เรียกใช้ฟังก์ชัน getOrderFields และ getOrderItems อีกครั้ง แต่จะอ่านผลลัพธ์จากแคชในเครื่องแทน ดังนั้น ทุกการเรียก getOrderFields หรือ getOrderItems ด้วย order_no=2108 จะได้รับการตอบสนองโดยแคชในเครื่องภายใน 24 ชั่วโมงนับจากนี้ (เนื่องจากอายุการใช้งานถูกตั้งค่าเป็น 86400 วินาที) อย่างไรก็ตาม โปรดทราบว่าคลาส Cache_Lite_Function ไม่ได้จัดเตรียม API เพื่อทดสอบว่าแคชพร้อมใช้งานสำหรับฟังก์ชันที่กำหนดพร้อมกับพารามิเตอร์ที่กำหนดหรือไม่ ดังนั้นจึงอาจเป็นเรื่องยากเล็กน้อยในการพิจารณาว่าแอปพลิเคชันอ่านแคชจริง ๆ หรือยังดำเนินการฟังก์ชันทุกครั้งที่เรียกใช้ด้วยพารามิเตอร์เดียวกัน ตัวอย่างเช่น ในตัวอย่างข้างต้น เพื่อให้แน่ใจว่ากลไกการแคชทำงานอย่างถูกต้อง คุณสามารถเปลี่ยนข้อมูลการเชื่อมต่อชั่วคราวที่ระบุในสคริปต์ Connect.php เพื่อไม่ให้สร้างการเชื่อมต่อฐานข้อมูลได้ ตัวอย่างเช่น ระบุชื่อโฮสต์เซิร์ฟเวอร์ฐานข้อมูลไม่ถูกต้อง จากนั้นใช้ order_no= อีกครั้ง 2108 เรียกใช้สคริปต์ testCache.php หากการแคชทำงานอย่างถูกต้อง ผลลัพธ์ของเบราว์เซอร์ควรจะเหมือนเดิม
นอกจากนี้ คุณสามารถตรวจสอบไดเร็กทอรีแคชที่ถูกส่งผ่านไปยังตัวสร้างของคลาส Cache_Lite_Function เป็นค่าของตัวเลือก cacheDir (/tmp ในตัวอย่างนี้) ในไดเร็กทอรีนั้น คุณจะพบไฟล์แคชสองไฟล์ที่คุณเพิ่งสร้างขึ้นโดยมีชื่อคล้ายกับ: cache_7b181b55b55aee36ad5e7bd9d5a091ec_3ad04d3024f4cd54296f75c92a359154 โปรดทราบว่าหากคุณเป็นผู้ใช้ Windows คุณอาจต้องการใช้ไดเรกทอรี %SystemDrive%temp เพื่อบันทึกไฟล์แคช หากเป็นเช่นนั้น ตัวเลือก cacheDir จะต้องตั้งค่าเป็น /temp/
หลังจากตรวจสอบว่ากลไกการแคชทำงานอย่างถูกต้องแล้ว คุณสามารถสร้าง PHP เพื่อจัดการการแจ้งเตือนการเปลี่ยนแปลงที่ได้รับจากเซิร์ฟเวอร์ฐานข้อมูลได้ "Listing 8" คือสคริปต์ dropResult.php เซิร์ฟเวอร์ฐานข้อมูลจะเรียกสคริปต์นี้เพื่อตอบสนองต่อการเปลี่ยนแปลงตาราง ORDERS และ ORDER_ITEMS
รายการ 8. การจัดการการแจ้งเตือนการเปลี่ยนแปลงที่ได้รับจากเซิร์ฟเวอร์ฐานข้อมูล
<?php
//ไฟล์:dropResults.php
need_once 'แคช/Lite/Function.php';
$options = array(
'cacheDir' => '/tmp/'
-
$cache = Cache_Lite_Function ใหม่($options);
ถ้า (isset($_GET['order_no'])&& isset($_GET['table'])) {
ถ้า($_GET['ตาราง']=='ORDER_ITEMS'){
$cache->drop('getOrderItems', $_GET['order_no']);
-
ถ้า ($_GET['ตาราง']=='คำสั่งซื้อ'){
$cache->drop('getOrderFields', $_GET['order_no']);
-
-
?
หลังจากสร้างสคริปต์ dropResult.php ตรวจสอบให้แน่ใจว่า URL ที่ระบุในตัวจัดการการแจ้งเตือน (แสดงในรายการ 2) ถูกต้อง จากนั้น เชื่อมต่อเป็น OE/OE ใน SQL*Plus หรือเครื่องมือที่คล้ายกัน และดำเนินการคำสั่ง UPDATE ที่จะส่งผลต่อคำสั่งซื้อเดียวกันที่เข้าถึงก่อนหน้านี้ในส่วนนี้ผ่านทางสคริปต์ testCache.php (นี่คือคำสั่งซื้อที่มี ID 2408):
UPDATE ORDERS SET order_mode = ' โดยตรง' WHERE order_id=2408;
อัปเดตจำนวน ORDER_ITEMS SET = 3 โดยที่ order_id=2408 และ line_item_id=1;
อัปเดตจำนวน ORDER_ITEMS SET = 1 โดยที่ order_id=2408 และ line_item_id=2;
ให้สัญญา;
เพื่อตอบสนองต่อการอัปเดตข้างต้น ตัวจัดการการแจ้งเตือนที่อธิบายไว้ก่อนหน้าในบทความนี้จะรันสคริปต์ dropResults.php สองครั้ง โดยใช้ URL ต่อไปนี้: http://webserverhost/phpcache/dropResults.php?order_no=2408&table=ORDERS
http://webserverhost/phpcache/dropresults.php?order_no=2408&table=ORDER_ITEMS
จาก "รายการ 8" คุณจะเห็นได้อย่างชัดเจนว่าสคริปต์ dropResult.php ไม่ได้ล้างแคชหลังจากได้รับการแจ้งเตือนการเปลี่ยนแปลงจากเซิร์ฟเวอร์ฐานข้อมูล เพียงลบไฟล์แคชที่มีข้อมูลที่หมดอายุ ดังนั้นหากคุณตรวจสอบไดเร็กทอรีแคชตอนนี้ คุณจะเห็นว่าไฟล์แคชที่สร้างขึ้นเมื่อเรียกใช้สคริปต์ testCache.php ที่มี order_no=2408 หายไป ความหมายโดยพื้นฐานก็คือในครั้งต่อไปที่ testCache.php ร้องขอข้อมูลที่เกี่ยวข้องกับรหัสคำสั่งซื้อ 2408 ก็จะได้รับข้อมูลนั้นจากฐานข้อมูลแบ็กเอนด์แทนที่จะเป็นแคชในเครื่อง
คุณอาจพบว่าวิธีนี้มีประโยชน์ในสถานการณ์ที่ชุดผลลัพธ์ที่แอปพลิเคชันร้องขอมีแนวโน้มที่จะเปลี่ยนแปลงก่อนที่แอปพลิเคชันจะใช้งาน สำหรับวัตถุประสงค์ของตัวอย่างของบทความนี้ หมายความว่าข้อมูลที่เกี่ยวข้องกับคำสั่งซื้อหนึ่งๆ อาจเปลี่ยนแปลงได้หลายครั้งก่อนที่ testCache.php จะเข้าถึงคำสั่งซื้อนั้น ด้วยวิธีนี้ แอปพลิเคชันจะทำงานที่ไม่จำเป็นจำนวนมากโดยการล้างแคชทันทีหลังจากได้รับการแจ้งเตือนการเปลี่ยนแปลงจากเซิร์ฟเวอร์ฐานข้อมูล
แต่ถ้าคุณต้องการให้สคริปต์ dropResult.php ล้างแคชทันทีที่ได้รับแจ้งถึงการเปลี่ยนแปลง คุณสามารถเรียกวิธีการเรียกของอินสแตนซ์ Cache_Lite_Function ได้หลังจากเรียกวิธี drop โดยระบุพารามิเตอร์เดียวกันสำหรับการโทรทั้งสองครั้ง ในกรณีนี้ คุณควรตรวจสอบให้แน่ใจว่าได้รวมสคริปต์ getOrderFields.php และ getOrderItems.php เพื่อให้ dropResults.php สามารถเรียกใช้ฟังก์ชัน getOrderFields และ getOrderItems เพื่อรีเฟรชแคชได้ "Listing 9" เป็นสคริปต์ dropResult.php ที่ถูกแก้ไข
รายการ 9. ล้างแคชทันทีหลังจากได้รับการแจ้งเตือนการเปลี่ยนแปลง
<?php
//ไฟล์:dropResults.php
need_once 'แคช/Lite/Function.php';
need_once 'getOrderItems.php';
need_once 'getOrderFields.php';
$options = อาร์เรย์(
'cacheDir' => '/tmp/',
'อายุการใช้งาน' => 86400
-
$cache = Cache_Lite_Function ใหม่($options);
ถ้า (isset($_GET['order_no'])&& isset($_GET['table'])) {
ถ้า($_GET['ตาราง']=='ORDER_ITEMS'){
$cache->drop('getOrderItems', $_GET['order_no']);
$cache->call('getOrderItems', $_GET['order_no']);
-
ถ้า ($_GET['ตาราง']=='คำสั่งซื้อ'){
$cache->drop('getOrderFields', $_GET['order_no']);
$cache->call('getOrderFields', $_GET['order_no']);
-
-
?
วิธีการข้างต้นอาจมีประโยชน์หากข้อมูลที่จัดเก็บไว้ในตาราง ORDERS และ ORDER_ITEMS แทบจะไม่เปลี่ยนแปลงและแอปพลิเคชันเข้าถึงข้อมูลบ่อยครั้ง
สรุป
หากแอปพลิเคชัน PHP ของคุณโต้ตอบกับ Oracle Database 10g Release 2 คุณสามารถใช้ประโยชน์จากคุณสมบัติการแจ้งเตือนการเปลี่ยนแปลงฐานข้อมูลได้ ซึ่งช่วยให้แอปพลิเคชันของคุณรับการแจ้งเตือนเพื่อตอบสนองต่อการเปลี่ยนแปลง DML ต่อออบเจ็กต์ที่เกี่ยวข้องกับคำขอที่ทำขึ้น เมื่อใช้คุณลักษณะนี้ คุณไม่จำเป็นต้องอัปเดตแคชในแอปพลิเคชันของคุณในช่วงเวลาที่กำหนด แต่การดำเนินการจะดำเนินการก็ต่อเมื่อชุดผลลัพธ์ของการสืบค้นที่ลงทะเบียนไว้มีการเปลี่ยนแปลงเท่านั้น