ใช้ ADOdb กับ PHP และ Oracle มีข้อดีเยอะมากมาย (1/2)
หน้าแรก PHP MySQL เกร็ดความรู้ ใช้ ADOdb กับ PHP และ Oracle มีข้อดีเยอะมากมาย (1/2)
เรียบเรียงจากเอกสารต้นฉบับ Using ADOdb with PHP and Oracle: an advanced tutorial " http://phplens.com/lens/adodb/docs-oracle.htm " โดยคุณ John Lim
ดังที่เราทราบกันว่า ออราเคิลนั้นเป็นระบบฐานข้อมูลที่ได้รับความนิยมในการใช้กับ PHP มากที่สุด ซึ่งมีหลากหลายวิธีที่สามารถเข้าถึงระบบฐานข้อมูลออราเคิลในการเขียนโปรแกรมด้วย PHP ซึ่งรวมทั้ง
- The oracle extension
- The oci8 extension
- PEAR DB library
- ADOdb library
ด้วยตัวเลือกที่หลากหลายทำความสับสนให้หลายคนที่เริ่มต้นใช้งานออราเคิลกับ PHP เราพอจะสรุปข้อแตกต่าง และแสดงให้เห็นถึงข้อดีในการเลือกใช้ ADOdb
อย่างแรก เรามี C extension ที่มีฟังก์ชันการเข้าถึงระบบฐานข้อมูลออราเคิลในระดับล่าง ซึ่ง C extension เหล่านี้ ถูก comply เข้าไปใน PHPอยู่ก่อนแล้ว หรือถูกโยงไว้โดยอัตโนมัติเมื่อเว็บเซิร์ฟเวอร์เริ่มทำงาน ในบางกรณี เราอาจจำเป็นต้องใช้ออราเคิล และ PHP บนลีนุกซ์ ซึ่งเราสามารถอ่านได้จากคำแนะนำในการติดตั้ง Oracle and PHP on Linuxได้
Oracle extension | ถูกออกแบบมาเพื่อ Oracle 7 หรือเวอร์ชันก่อนหน้านั้น ซึ่งถูกยกเลิกการใช้งานไปแล้ว |
Oci8 extension | นอกจากชื่อที่ใช้ได้เพียงกับ Oracle 8i แล้ว extension นี้ยังเป็นมาตรฐานในการเข้าถึงระบบฐานข้อมูลที่ทำงานอยู่บน Oracle 8i, 9i หรือ 10g และเวอร์ชันหลังจากนี้ได้ด้วย |
นี่เป็นตัวอย่างที่ใช้ oci8 extension การเรียกดูข้อมูลในตารางข้อมูล emp ซึ่งอยู่ใน schema ชื่อ scott โดยใช้พารามิเตอร์แบบ bind
$conn = OCILogon("scott","tiger", $tnsName); $stmt = OCIParse($conn,"select * from emp where empno > :emp order by empno"); $emp = 7900; OCIBindByName($stmt, ':emp', $emp); $ok = OCIExecute($stmt); while (OCIFetchInto($stmt,$arr)) { print_r($arr); echo " "; } |
ซึ่งผลลัพธ์ที่ได้จะมีลักษณะดังนี้
Array ( [0] => 7902 [1] => FORD [2] => ANALYST [3] => 7566 [4] => 03/DEC/81 [5] => 3000 [7] => 20 ) -------------------------------------------------------------------------------------------------------------------------------------- Array ( [0] => 7934 [1] => MILLER [2] => CLERK [3] => 7782 [4] => 23/JAN/82 [5] => 1300 [7] => 10 ) |
เรายังมี PHP library ในระดับสูงอีกหลายตัวที่อนุญาตให้เราสามารถแก้ไขโปรแกรมข้างบนได้้ง่ายขึ้น ซึ่งวิธีที่เป็นที่นิยมมากที่สุดก็คือPEAR DB และ ADOdb และนี่คือข้อแตกต่างระหว่าง library ทั้งสอง
คุณลักษณะ | PEAR DB 1.6 | ADOdb 4.52 |
รูปแบบทั่วไป | ไม่ซับซ้อน ง่ายต่อการใช้งาน ขาดฟังก์ชันเฉพาะของออราเคิล | ออกแบบแบบ multi-tier ไม่ซับซ้อน ถูกออกแบบมาแบบระดับสูงสำหรับผู้เริ่มต้น และแบบระดับล่างสำหรับฟังก์ชันการใช้งานของออราเคิลในขั้นสูง |
สนับสนุนการเตรียมชุดคำสั่ง | ใช่ แต่เพียงแค่หนึ่งชุดคำสั่ง เพราะชุดคำสั่งล่าสุด จะทำงานทับชุดคำสั่งก่อนหน้านั้น | ใช่ สามารถเตรียมชุดคำสั่งได้มากมาย |
สนับสนุนการใช้ LOBs | ไม่ | ใช่ โดยใช้ update semantics |
สนับสนุนการใช้ REF Cursors | ไม่ | ใช่ |
สนับสนุนการใช้พารามิเตอร์นำเข้า | ใช่ | ใช่ |
สนับสนุนการใช้พารามิเตอร์ส่งออก | ใช่ | ใช่ |
การสร้าง schema โดยใช้ XML | ไม่ | ใช่ รวมถึงความสามารถในการระบุ tablespaces และconstrains |
มี database portability features | ไม่ | ใช่ มีความสามารถในการใช้งานแบบ abstract features ซึ่งแสดงความแตกต่างระหว่างระบบฐานข้อมูล เช่น วันที่ การเชื่อมพารามิเตอร์แบบbind และชนิดของข้อมูล |
ทำการ monitor และ tracing | ไม่ | ใช่ สามารถติดตามการใช้SQL และเชื่อมโยงไปยังเว็บเพจที่สั่งให้ทำงาน SQLนั้น รวมทั้งอธิบายแนวทางแก้ไข |
การ cache ข้อมูล recordsetสำหรับข้อมูลที่ถูกเรียกใช้งานบ่อย | ไม่ | ใช่ ทำให้การสั่ง SQL ได้ผลลัพธ์เร็วขึ้น รวมทั้ง SQLที่มีเงื่อนไข where, group-byและ order-by ที่ซับซ้อน |
ความนิยมใช้ | ใช่ เป็นส่วนหนึ่งของ PEARที่ถูกนำมาใช้งาน | ใช่ โครงการ open sourceหลายโครงการกำลังใช้ซอฟต์แวร์ตัวนี้ ซึ่งหมายรวมถึง PostNuke, Xaraya, Mambo และ Tiki Wiki |
ความเร็ว | ปานกลาง | เร็วมาก มี abstraction libraryของระบบฐานข้อมูลที่รวดเร็วที่สุดสำหรับ PHP ซึ่งสามารถดูรายละเอียดได้ในBenchmarks |
มี extension ความเร็วสูง | ไม่ | ใช่ เราสามารถติดตั้งADOdb extension ซึ่งพัฒนาส่วนของ ADOdb ที่ถูกใช้งานบ่อยมากที่สุดราวกับความเร็วของภาษา C |
PEAR DB นั้นใช้งานได้ดีสำหรับเว็บแอพลิเคชันธรรมดาทั่วไป แต่หากเราต้องการประสิทธิภาพที่มากกว่านั้น เราจะเห็นว่า ADOdb นั้นมีฟังก์ชันการทำงานที่ซับซ้อนมากกว่า ในบทความต่อไปนี้จะกล่าวถึงการใช้ ADOdb กับระบบฐานข้อมูลออราเคิลเป็นส่วนใหญ่ เราสามารถหาข้อมูลเกี่ยวกับการติดต่อระบบฐานข้อมูลออราเคิลได้ภายหลังจากอ่านบทความนี้แล้ว
ตัวอย่าง ADOdb
จากตัวอย่าง oci8 ข้างบนซึ่งเรียกดูข้อมูลจากตารางข้อมูล emp สามารถเขียนแบบ ADOdb ได้ดังนี้
include "/path/to/adodb.inc.php"; $db = NewADOConnection("oci8"); $db->Connect($tnsName, "scott", "tiger"); $rs = $db->Execute("select * from emp where empno>:emp order by empno", array('emp' => 7900)); while ($arr = $rs->FetchRow()) { print_r($arr); echo " "; } |
ฟังก์ชัน Execute() จะคืนค่าออกมาเป็น recordset และเราสามารถดึงแถวที่ถูกคืนกลับมาได้โดยใช้คำสั่ง $recordset->FetchRow()
ถ้าเราไม่ใช้การสร้างการติดต่อเริ่มแรก เราจะเห็นว่าการทำงานแบบ ADOdb นั้นง่าย และไม่ยุ่งยากเลย
Oci8 | ADOdb |
$stmt = OCIParse($conn, "select * from emp where empno > :emp"); $emp = 7900; OCIBindByName($stmt, ':emp', $emp); $ok = OCIExecute($stmt); while (OCIFetchInto($stmt,$arr)) { print_r($arr); echo " "; } | $recordset = $db->Execute("select * fromemp where empno>:emp", array('emp' => 7900)); while ($arr = $recordset->FetchRow()) { print_r($arr); echo " "; } |
เราสามารถเรียกดูข้อมูลในระบบฐานข้อมูลโดยใช้มาตรฐาน Microsoft ADO MoveNext() ชุดข้อมูลในแถวปัจจุบันจะถูกจัดเก็บไว้ในค่าFields ของ recordset object หรือ $rs ฟังก์ชัน MoveNext() จะให้ประสิทธิภาพการทำงานที่สูงที่สุดในบรรดาเทคโนโลยีอื่นๆ ที่ทำงานผ่านrecordset
$rs = $db->Execute("select * from emp where empno>:emp", array('emp' => 7900)); while (!$rs->EOF) { print_r($rs->fields); $rs->MoveNext(); } |
และหากเราต้องการให้ข้อมูลที่คืนค่ากลับมาอยู่ในรูปชุดข้อมูลสองมิติ เราสามารถใช้
$arr = $db->GetArray("select * from emp where empno>:emp", array('emp' => 7900)); |
ซึ่งจะมีแถวข้อมูลแรกเท่านั้นที่เป็นชุดข้อมูล
$arr = $db->GetRow("select * from emp where empno=:emp", array('emp' => 7900)); |
หรือจะดึงข้อมูลเฉพาะฟิล์ดแรกของแถวข้อมูลแรก
$arr = $db->GetOne("select ename from emp where empno=:emp", array('emp' => 7900)); |
และเพื่อให้ง่ายในการทำรายงานเป็นหน้า เรามีฟังก์ชัน SelectLimit ไว้ให้ใช้งาน ตัวอย่างต่อไปนี้จะทำการเรียกข้อมูล โดยจำกัดข้อมูลที่100 แถว เริ่มจากแถวที่ 200 เป็นต้นไป
$offset = 200; $limitrows = 100; $rs = $db->SelectLimit('select * from table', $offset, $limitrows); |
ค่าพารามิเตอร์ $limitrows เป็นตัวเลือก จะกำหนดหรือไม่ก็ได้
Array Fetch Mode
เมื่อข้อมูลถูกคืนค่าออกมาเป็นชุดข้อมูล เราสามารถเลือกชนิดของชุดข้อมูลที่จะถูกคืนกลับมาได้ในลักษณะดังนี้
- ดัชนีตัวเลข โดยใช้ $connection->SetFetchMode(ADODB_FETCH_NUM)
- ดัชนีสมทบ โดยคีย์ของชุดข้อมูลจะเป็นชื่อของฟิล์ด (เป็นตัวอักษรใหญ่) ใช้ $connection->SetFetchMode(ADODB_FETCH_ASSOC)
- ดัชนีตัวเลขและสมทบ ใช้ $connection->SetFetchMode(ADODB_FETCH_BOTH)
ออราเคิลใช้ ADODB_FETCH_BOTH เป็นค่าปริยาย
Caching
เราสามารถระบุไดเรกทอรีสำหรับ Cache ของระบบฐานข้อมูลได้ โดยใช้ $ADODB_CACHE_DIR และเก็บค่าผลลัพธ์ของ query ที่ถูกเรียกใช้บ่อยและไม่ค่อยมีการเปลี่ยนแปลงนัก ซึ่งเป็นประโยชน์อย่างยิ่งกับ SQL ที่มีความซับซ้อนของเงื่อนไข และการใช้กลุ่มข้อมูล และการเรียงลำดับข้อมูล และยังเป็นข้อดีในการลดการทำงานของดาตาเบสเซิร์ฟเวอร์
ตัวอย่างนี้จะเก็บ Cache ของชุดคำสั่ง select ข้อมูลเป็นเวลา 3,600 วินาที หรือ 1 ชั่วโมง
$ADODB_CACHE_DIR = '/var/adodb/tmp'; $rs = $db->CacheExecute(3600, "select names from allcountries order by 1"); |
นอกจากนี้ยังมีฟังก์ชันที่ทำงานใกล้เคียงกัน คือ CacheGetArray( ), CacheGetRow( ), CacheGetOne( ) and CacheSelectLimit( ) พารามิเตอร์ตัวแรกเป็นตัวเลขวินาทีที่จะทำ cache เราสามารถส่งชุดข้อมูล bind เป็นพารามิเตอร์ตัวที่สามได้ด้วย แต่ไม่ได้แสดงไว้ในตัวอย่างข้างบน
เรามีทางเลือกสำหรับการทำงาน cache อีก โดยพารามิเตอร์ตัวแรกถูกละเว้นไว้ และเรากำหนดค่า cacheSecs ของการติดต่อได้ดังนี้
$ADODB_CACHE_DIR = '/var/adodb/tmp'; $connection->cacheSecs = 3600; $rs = $connection->CacheExecute($sql, array('id' => 1)); |
3. Using Prepare() For Frequently Used Statement
คำสั่ง Prepare() ใช้สำหรับการ comply ชุดคำสั่ง SQL ที่ถูกเรียกใช้บ่อย เพื่อพร้อมสำหรับการถูกเรียกใช้ใหม่ ตัวอย่างเช่น เรามี array ชุดใหญ่ที่จำเป็นต้องนำเข้าไปจัดเก็บไว้ในระบบฐานข้อมูลออราเคิล ตัวอย่างต่อไปนี้เป็นผลจากการสั่งการเรียกข้อมูลขนาดใหญ่อย่างน้อย20-40% ซึ่งชุดคำสั่ง SQL จำเป็นต้องถูก comply เพียงแค่ครั้งเดียว
$stmt = $db->Prepare('insert into table (field1, field2) values (:f1, :f2)'); foreach ($arrayToInsert as $key => $value) { $db->Execute($stmt, array('f1' => $key, 'f2' => $val); } |
ระบบฐานข้อมูลออราเคิลจะเก็บรักษาข้อมูลที่มีขนาดมากกว่า 4,000 ไบท์ในลักษณะพิเศษ ซึ่งเรียกว่า Large Objects หรือเรียกสั้นๆ ว่าLOBs ส่วน LOBs ที่เป็น binary จะเรียกว่า BLOBs และ LOBs ที่เป็น character จะเรียกว่า CLOBs ถ้าหากเราใช้ library ของออราเคิล เราจำเป็นต้องใช้โพรเซสจำนวนมากในการทำงานกับ LOBs อาจเป็นเพราะออราเคิลได้ออกแบบให้มันทำงานภายในระบบโดยใช้หน่วยความจำที่น้อยที่สุด ADOdb มีหลายส่วนที่ทำให้การใช้ LOBs เป็นไปได้ง่ายขึ้น
ADOdb จะจัดการ LOBs โดยใช้ชุดคำสั่ง SQL ทำให้ LOBs ถูกแปลงเป็นค่าตัวแปรใน PHP อย่างอัตโนมัติ โดยที่เราไม่ต้องทำการเขียนโปรแกรมเพิ่มแต่อย่างใด
ส่วนการปรับปรุงเปลี่ยนแปลงข้อมูลใน LOBs จะมีฟังก์ชัน UpdateBlob() และ UpdateClob() ไว้ให้ใช้งาน ตัวอย่างต่อไปนี้เป็นตัวอย่างเกี่ยวกับ BLOB ซึ่งค่าพารามิเตอร์ต่างๆ จะอธิบายอยู่ในตัวอยู่แล้ว
$ok = $db->Execute("insert into aTable (id, name, ablob) values (aSequence.nextVal, 'Name', null)"); if (!$ok) return LogError($db->ErrorMsg()); # params: $tableName, $blobFieldName, $blobValue, $whereClause $db->UpdateBlob('aTable', 'ablob', $blobValue, 'id=aSequence.currVal'); |
และหากเป็น CLOB จะมีลักษณะดังนี้
$ok = $db->Execute("insert into aTable (id, name, aclob) values (aSequence.nextVal, 'Name', null)"); if (!$ok) return LogError($db->ErrorMsg()); $db->UpdateClob('aTable', 'aclob', $clobValue, 'id=aSequence.currVal'); |
หมายเหตุ: ฟังก์ชัน LogError() เป็นฟังก์ชันที่สร้างขึ้นมาเอง ไม่เกี่ยวกับ ADOdb แต่อย่างใด
การนำเข้าข้อมูลแบบ LOBs จะยุ่งยากกว่า โดย ADOdb ตั้งแต่ ADOdb 4.55 ขึ้นไป เราสามารถนำเข้าข้อมูลแบบ LOBs ได้ จากตัวอย่าง สมมติว่า ฟิลด์ที่เป็นรูปภาพนั้นเป็น BLOB และเราต้องการจัดเก็บ $blob_data เข้าไปในฟิลด์นี้ และคีย์หลักคือ ฟิล์ด id
$sql = "INSERT INTO photos ( ID, photo) ". "VALUES ( :id, empty_blob() )". " RETURNING photo INTO :xx"; $stmt = $db->PrepareSP($sql); $db->InParameter($stmt, $id, 'id'); $blob = $db->InParameter($stmt, $blob_data, 'xx',-1, OCI_B_BLOB); $db->StartTrans(); $ok = $db->Execute($stmt); $db->CompleteTrans(); |
ตัว Recordsets ของออราเคิล สามารถถูกส่งผ่านเป็นตัวแปรที่เรียกว่า REF Cursors ตัวอย่างเช่น ใน PL/SQL เราสามารถกำหนดฟังก์ชันopen_tab ที่คืนค่า REF CURSOR มาในพารามิเตอร์ตัวแรก
TYPE TabType IS REF CURSOR RETURN TAB%ROWTYPE; PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames IN VARCHAR) IS BEGIN OPEN tabcursor FOR SELECT * FROM TAB WHERE tname LIKE tablenames; END open_tab; |
ใน ADOdb เราสามารถเข้าถึง REF Cursor ได้โดยใช้ฟังก์ชัน ExecuteCursor ตัวอย่างต่อไปจะเป็นการหาชื่อตารางข้อมูลทั้งหมดที่เริ่มต้นด้วยตัวอักษร "A" ที่อยู่ใน schema ปัจจุบัน
$rs = $db->ExecuteCursor("BEGIN open_tab(:refc,'A%'); END;",'refc'); while ($arr = $rs->FetchRow()) print_r($arr); |
พารามิเตอร์ตัวแรกคือ ชุดคำสั่ง PL/SQL และพารามิเตอร์ตัวที่สองคือ ชื่อของ REF Cursor
จาก http://www.exzilla.net/docs/adodb/adodb-oracle-tutorial.php
ขึ้นไปด้านบน
