ใช้ 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

1.      Introduction

ดังที่เราทราบกันว่า ออราเคิลนั้นเป็นระบบฐานข้อมูลที่ได้รับความนิยมในการใช้กับ 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หลายโครงการกำลังใช้ซอฟต์แวร์ตัวนี้ ซึ่งหมายรวมถึง PostNukeXaraya, 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 "


";

}

2.      ADOdb Query Semantics

เราสามารถเรียกดูข้อมูลในระบบฐานข้อมูลโดยใช้มาตรฐาน 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

เมื่อข้อมูลถูกคืนค่าออกมาเป็นชุดข้อมูล เราสามารถเลือกชนิดของชุดข้อมูลที่จะถูกคืนกลับมาได้ในลักษณะดังนี้

  1. ดัชนีตัวเลข โดยใช้ $connection->SetFetchMode(ADODB_FETCH_NUM)
  2. ดัชนีสมทบ โดยคีย์ของชุดข้อมูลจะเป็นชื่อของฟิล์ด (เป็นตัวอักษรใหญ่) ใช้ $connection->SetFetchMode(ADODB_FETCH_ASSOC)
  3. ดัชนีตัวเลขและสมทบ ใช้ $connection->SetFetchMode(ADODB_FETCH_BOTH)

ออราเคิลใช้ ADODB_FETCH_BOTH เป็นค่าปริยาย

Caching

เราสามารถระบุไดเรกทอรีสำหรับ Cache ของระบบฐานข้อมูลได้ โดยใช้ $ADODB_CACHE_DIR และเก็บค่าผลลัพธ์ของ query ที่ถูกเรียกใช้บ่อยและไม่ค่อยมีการเปลี่ยนแปลงนัก ซึ่งเป็นประโยชน์อย่างยิ่งกับ SQL ที่มีความซับซ้อนของเงื่อนไข และการใช้กลุ่มข้อมูล และการเรียงลำดับข้อมูล และยังเป็นข้อดีในการลดการทำงานของดาตาเบสเซิร์ฟเวอร์

ตัวอย่างนี้จะเก็บ Cache ของชุดคำสั่ง select ข้อมูลเป็นเวลา 3,600 วินาที หรือ ชั่วโมง

$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.      Working with LOBs

ระบบฐานข้อมูลออราเคิลจะเก็บรักษาข้อมูลที่มีขนาดมากกว่า 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();

5.      REF CURSORs

ตัว 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



ขึ้นไปด้านบน