Using ADOdb with PHP and Oracle: an advanced tutorial (ภาษาไทย)


หน้าแรก Oracle Using ADOdb with PHP and Oracle: an advanced tutorial (ภาษาไทย)

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 ในระดับสูงอีกหลายตัวที่อนุญาตให้เราสามารถแก้ไขโปรแกรมข้างบนได้้ง่ายขึ้น

เราสามารถติดตั้ง 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 * from emp 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
เมื่อข้อมูลถูกคืนค่าออกมาเป็นชุดข้อมูล เราสามารถเลือกชนิดของชุดข้อมูลที่จะถูกคืนกลับมาได้ในลักษณะดังนี้
ดัชนีตัวเลข โดยใช้ $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. 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


6. In and Out Parameters
PL/SQL stored procedure ต่อไปนี้ต้องการตัวแปรนำเข้า และคืนค่ามาเป็นตัวแปรส่งออก
PROCEDURE data_out(input IN VARCHAR, output OUT VARCHAR) IS
BEGIN
output := 'I love 'input;
END;
ตัวอย่างโปรแกรม ADOdb ต่อไป แสดงการเรียก stored procedure
$stmt = $db->PrepareSP("BEGIN adodb.data_out(:a1, :a2); END;");
$input = 'Sophia Loren';
$db->InParameter($stmt,$input,'a1');
$db->OutParameter($stmt,$output,'a2');
$ok = $db->Execute($stmt);
if ($ok) echo ($output == 'I love Sophia Loren') ? 'OK' : 'Failed';
ฟังก์ชัน PrepareSP() เป็นฟังก์ชันพิเศษที่รู้เกี่ยวกับค่าพารามิเตอร์แบบ bind ซึ่งข้อจำกัดหลักที่มีอยู่ตอนนี้ก็คือ พารามิเตอร์ IN OUT ยังทำงานไม่ได้
Bind Parameters และ REF CURSORs
เราสามารถเขียนตัวอย่าง REF CURSOR ใหม่ โดยใช้ InParameter (ซึ่งต้องใช้กับ ADOdb 4.53 ขึ้นไป) ใหม่ได้ดังนี้
$stmt = $db->PrepareSP("BEGIN adodb.open_tab(:refc,:tabname); END;");
$input = 'A%';
$db->InParameter($stmt,$input,'tabname');
$rs = $db->ExecuteCursor($stmt,'refc');
while ($arr = $rs->FetchRow()) print_r($arr);
Bind Parameters และ LOBs
เรายังสามารถทำงานบน LOBs ดังตัวอย่างต่อไปนี้ เรามีพารามิเตอร์ IN และ OUT ที่เป็น CLOBs
$text = 'test test test';
$sql = "declare rs clob; begin :rs := lobinout(:sa0); end;";
$stmt = $conn -> PrepareSP($sql);
$conn -> InParameter($stmt,$text,'sa0', -1, OCI_B_CLOB); # -1 means variable length
$rs = '';
$conn -> OutParameter($stmt,$rs,'rs', -1, OCI_B_CLOB);
$conn -> Execute($stmt);
echo "return = ".$rs."
";
เราสามารถใช้ OCI_B_BLOB ในการระบุว่า เรากำลังใช้ BLOBs ได้ด้วยเช่นกัน
การนำมาใช้ใหม่ของ Bind Parameters กับ CURSOR_SHARING=FORCE
เว็บโปรแกรมเมอร์หลายรายไม่สนใจที่จะใช้พารามิเตอร์แบบ bind และต้องการที่จะใส่ค่าไปใน SQL โดยตรง ดังนั้นแทนที่เราจะเขียนโปรแกรมแบบนี้
$arr = $db->GetArray("select * from emp where empno>:emp", array('emp' => 7900));
ก็สามารถใส่ค่าข้อมูลเข้าไปใน SQL ได้ดังนี้
$arr = $db->GetArray("select * from emp where empno>7900");
การทำเช่นนี้จะลดประสิทธิภาพการทำงานของออราเคิล เพราะว่าออราเคิลจะใช้ SQL ที่ comply แล้วนำมาใช้ใหม่ ซึ่งระบุไปยัง SQL ที่ comply ไปก่อนหน้านี้แล้ว ตัวอย่างข้างบนที่มีค่าของข้อมูลอยู่ใน SQL จะไม่ได้ถูกนำมาใช้ใหม่จริง และจากการปรับเปลี่ยนให้เหมาะสม ออราเคิลตั้งแต่เวอร์ชัน 8.1 เป็นต้นไป เราสามารถกำหนดพารามิเตอร์แบบ session ได้หลังจากที่เราเข้าสู่ระบบแล้ว
ALTER SESSION SET CURSOR_SHARING=FORCE
ด้วยการกำหนดแบบนี้ ทำให้ออราเคิลแปลงค่าตัวแปรทั้งหมด (เช่น ค่า 7900) ให้เป็นค่าพารามิเตอร์แบบ bind เพื่อปรับปรุงประสิทธิภาพการนำ SQL มาใช้ใหม่
รายละเอียดเกี่ยวกับ Speedup Tips


7. Dates and Datetime in ADOdb
ใน ADOdb มีสองสิ่งที่เราจำเป็นต้องทำความเข้าใจเกี่ยวกับข้อมูลวันที่ อย่างแรกก็คือ ต้องมั่นใจว่า ข้อมูลในระบบฐานข้อมูลต่างๆ นั้นใช้ร่วมกันได้ ซึ่ง ADOdb ตั้งสมมติฐานว่า ข้อมูลวันที่จะคืนค่ามาในรูปแบบ ISO นั่นคือ YYYY-MM-DD H24:MI:SS
อย่างที่สองก็คือ เนื่องจากระบบฐานข้อมูลออราเคิลเก็บข้อมูลวันที่และเวลาโดยใช้ชนิดข้อมูลเดียวกัน เราจึงตัดสินใจไม่แสดงค่าเวลาในข้อมูลรูปแบบวันที่ที่เป็นค่าปริยาย ดังนั้นเมื่อเข้าสู่ระบบ ADOdb จะกำหนดค่า NLS_DATE_FORMAT ให้เป็น 'YYYY-MM-DD' ในตัวอย่างต่อไปนี้ จะเป็นการแสดงค่าวันที่ และเวลาที่เป็นค่าปริยาย
$db = NewADOConnection('oci8');
$db->NLS_DATE_FORMAT = 'RRRR-MM-DD HH24:MI:SS';
$db->Connect($tns, $user, $pwd);
หรือจะสั่งโดย
$sql = "ALTER SESSION SET NLS_DATE_FORMAT = 'RRRR-MM-DD HH24:MI:SS'";
$db->Execute($sql);
ถ้าเราไม่สนใจเรื่องวันที่ที่เป็น Portability และไม่ได้ใช้ portability layer ของ ADOdb เราสามารถใช้รูปแบบวันที่ที่เราต้องการได้เลย


8. Database Portability Layer
ADOdb มีฟังก์ชันสำหรับช่วยสร้างฟังก์ชัน SQL ที่คืนค่ามาเป็น string ให้เราสามารถนำมารวมเข้ากับชุดคำสั่ง SQL ของเราเองได้ด้วย
ฟังก์ชัน

คำอธิบาย
DBDate($date)
ส่งค่าเวลาในยูนิกซ์ หรือวันที่แบบ ISO ฟังก์ชันจะแปลงให้เป็นข้อมูลวันที่ในรูปแบบ string เพื่อใช้ในการ INSERT/UPDATE

DBTimeStamp($date)
ส่งค่าเวลาในยูนิกซ์ หรือวันที่แบบ ISO ฟังก์ชันจะแปลงให้เป็นข้อมูลเวลาในรูปแบบ string เพื่อใช้ในการ INSERT/UPDATE

SQLDate($date, $fmt)
สร้างรูปแบบวันที่โดยให้อยู่ในรูปแบบ $fmt ใช้สำหรับชุดคำสั่ง SELECT

OffsetDate($date, $ndays)
สร้าง offset $date โดย $ndays

Concat($s1, $s2,...)
รวมข้อมูลเข้าด้วยกัน หรืออาจจะใช้ไดรเวอร์ mssqlpo สำหรับ mssql ซึ่งอนุญาตให้ใช้ ได้

IfNull($fld, $replaceNull)
คืนค่า string ฟังก์ชันนี้เทียบเท่ากับ IFNULL ใน MySQL หรือ NVL ของออราเคิล

Param($name)
สร้าง bind placeholders โดยใช้ ? หรือชื่อที่ตั้งไว้ตามความเหมาะสม

$db->sysDate
ค่าที่เก็บฟังก์ชัน SQL ที่คืนค่าวันที่ ณ ปัจจุบัน

$db->sysTimeStamp
ค่าที่เก็บฟังก์ชัน SQL ที่คืนค่าวันและเวลา ณ ปัจจุบัน

$db->concat_operator
ค่าที่เก็บตัวปฏิบัติการรวมข้อมูลเข้าด้วยกัน

$db->length
ค่าที่เก็บชื่อของฟังก์ชัน SQL strlen

$db->uppercase
ค่าที่เก็บชื่อของฟังก์ชัน SQL strtoupper

$db->random
ค่าที่เก็บ SQL ในการสร้างตัวเลขสุ่มระหว่าง 0.00 ถึง 1.00

$db->substr
ค่าที่เก็บชื่อฟังก์ชันของ SQL substring


ADOdb ยังมี Oracle oci8 drivers อีกหลายตัว เพื่อใช้ในงานที่แตกต่างกันออกไปดังนี้
ชื่อไดรเวอร์
คำอธิบาย
oci805
สำหรับ Oracle 8.0.5 ซึ่งไดรเวอร์นี้จะมี SelectLimit() ที่ทำงานช้ากว่า

oci8
เป็นไดรเวอร์ที่ให้ประสิทธิภาพสูงสุด ซึ่งเป็นไดรเวอร์ปริยาย ค่าคีย์ที่ได้รับคืนจากชุดข้อมูลใน recordset จะอยู่ในรูปแบบตัวอักษรใหญ่ทั้งหมด

oci8po
เป็นไดรเวอร์แบบ portable ของออราเคิล ช้ากว่า oci8 นิดหน่อย ซึ่งไดรเวอร์นี้จะใช้ ? แทน :bindvar สำหรับค่าตัวแปร bind ซึ่งเป็นมาตรฐานของ

ระบบฐานข้อมูลอื่นๆ และค่าคีย์ที่ได้รับคืนจากชุดข้อมูลจะเป็นตัวอักษรเล็กทั้งหมด เหมือนระบบฐานข้อมูลอื่น
ต่อไปเป็นตัวอย่างการเรียกใช้ oci8po driver
$db = NewADOConnection('oci8po');
$db->Connect($tns, $user, $pwd);
$db->Execute("insert into atable (f1, f2) values (?,?)", array(12, 'abc'));
หมายเหตุ: ค่าตัวแปร bind ใช้เครื่องหมายคำถามแทน


9. Connecting to Oracle
ก่อนที่เราจะสามารถใช้ ADOdb เราต้องมี Oracle Client ติดตั้งอยู่ก่อนแล้ว และมีการติดตั้ง oci8 extension ด้วย ซึ่งมีมาแบบ pre-complied สำหรับ windows แต่เราก็ยังจำเป็นต้องกำหนดให้มันทำงานได้ในไฟล์ php.ini สำหรับตัวอย่างการ comply oci8 extension สำหรับ PHP และ Apache บนยูนิกซ์ สามารถอ่านรายละเอียดได้ที่ oracle.com
การใช้ Persistent Connections
เรามักพบคำถามที่ถามกันบ่อยๆ ก็คือ เราควรจะใช้การติดต่อแบบถาวรไปยังระบบฐานข้อมูลออราเคิลหรือไม่ ด้วยการติดต่อแบบถาวรที่อนุญาตให้ PHP ใช้การติดต่อที่มีอยู่แล้วได้อีก โดยเรียกใช้หลังจากที่เว็บเพจก่อนหน้านี้ได้ถูกเรียกให้ทำงานเสร็จอย่างสมบูรณ์ การติดต่อแบบไม่ถาวรจะปิดการติดต่ออัตโนมัติหลังจากเว็บเพจนั้นถูกเรียกให้ทำงาน การติดต่อแบบถาวรจะเร็วกว่า เพราะว่าเวลาที่ใช้ในการติดต่อใหม่แต่ละครั้งนั้นนานพอสมควร แต่การติดต่อแบบถาวรนี้ก็มีการใช้ทรัพยากรที่มากกว่า ออราเคิลอนุญาตให้เราใช้งานร่วมกัน และนำมาใช้ซ้ำได้อีกในเซิร์ฟเวอร์โพรเซส ซึ่งเรียกว่า Shared Server หรือที่รู้จักกันในนาม MTS
จากการทำ benchmarks ของผู้เขียน ขอแนะนำให้ใช้การติดต่อแบบไม่ถาวร และกำหนดการใช้งานแบบ Shared Server ซึ่งจะให้ประสิทธิภาพสูงสุด ถ้าไม่ได้เลือกใช้ Shared Server จึงควรจะพิจารณาการติดต่อแบบถาวร
ตัวอย่างการติดต่อ
ในกรณีที่มีปัญหาเรื่องการติดต่อไปยังระบบฐานข้อมูลออราเคิล เรามีตัวอย่างการสร้างการติดต่อดังนี้
a. PHP และ Oracle ถูกติดตั้งอยู่บนเครื่องเดียวกัน ใช้ SID ที่เป็นค่าปริยาย โดยใช้การติดต่อแบบไม่ถาวร
$conn = NewADOConnection('oci8');
$conn->Connect(false, 'scott', 'tiger');
b. TNS Name ที่ถูกกำหนดไว้ใน tnsnames.ora หรือ ONAMES หรือ HOSTNAMES ตัวอย่างเช่น 'myTNS' โดยใช้การติดต่อแบบถาวร
$conn = NewADOConnection('oci8');
$conn->PConnect(false, 'scott', 'tiger', 'myTNS');
หรือ
$conn->PConnect('myTNS', 'scott', 'tiger');
c. Host Address และ SID
$conn->Connect('192.168.0.1', 'scott', 'tiger', 'SID');
d. Host Address และ Service Name
$conn->Connect('192.168.0.1', 'scott', 'tiger', 'servicename');
e. Oracle connection string
$cstr = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=$host)
(PORT=$port))(CONNECT_DATA=(SID=$sid)))";
$conn->Connect($cstr, 'scott', 'tiger');
f. ADOdb data source name (dns)
$dsn = 'oci8://user:pwd@tnsname/?persist'; # persist is optional
$conn = ADONewConnection($dsn); # no need for Connect/PConnect
$dsn = 'oci8://user:pwd@host/sid';
$conn = ADONewConnection($dsn);
$dsn = 'oci8://user:pwd@/'; # oracle on local machine
$conn = ADONewConnection($dsn);
ถ้าหากใช้ ADOdb data source names ไม่ต้องใช้คำสั่ง Connect() และ PConnect()


10. Error Checking
ตัวอย่างในบทความนี้ง่ายต่อการทำความเข้าใจ แต่อาจจะดูง่ายไปหน่อย เพราะเราได้ละเรื่องการจัดการข้อผิดพลาดที่เกิดขึ้น คำสั่ง Execute() และ Connect() จะให้ค่า false หากเกิดข้อผิดพลาดขึ้น ดังนั้น การเรียกใช้ Connect() และ Excecute() ในความเป็นจริง ควรจะมีลักษณะดังนี้
function InvokeErrorHandler()
{global $db; ## assume global
MyLogFunction($db->ErrorNo(), $db->ErrorMsg());
}
if (!$db->Connect($tns, $usr, $pwd)) InvokeErrorHandler();
$rs = $db->Execute("select * from emp where empno>:emp order by empno",
array('emp' => 7900));
if (!$rs) return InvokeErrorHandler();
while ($arr = $rs->FetchRow()) {
print_r($arr);
echo "";
}
ท่านสามารถดึงข้อความของข้อผิดพลาด และหมายเลขข้อผิดพลาดของคำสั่ง SQL ที่ถูกสั่งให้ทำงานล่าสุดได้จาก ErrorMsg() และ ErrorNo() นอกจากนี้ ท่านยังสามารถสร้างฟังก์ชันการจัดการข้อผิดพลาดขึ้นมาเองก็ได้ และ ADOdb ก็ยังสนับสนุนการจัดการเกี่ยวกับเงื่อนไขใน PHP5 ด้วยเช่นกัน
การจัดการ Recordsets ขนาดใหญ่
เนื่องจาก oci8 driver ไม่สนับสนุนการนับจำนวนเรคคอร์ดข้อมูลออกมาในคำสั่ง SELECT จึงมีการสร้างฟังก์ชัน RecordCount() ขึ้นมา โดยเมื่อมีการกำหนดตัวแปร global $ADODB_COUNTRECS ให้เป็น true ซึ่งเป็นค่าปริยายอยู่แล้ว เราสร้างฟังก์ชันนี้ขึ้นมาโดยเก็บสำรองข้อมูลทุกเรคคอร์ด ทำให้สามารถใช้หน่วยความจำขนาดใหญ่เพื่อจัดเก็บข้อมูลจำนวนมากได้ แต่อย่างไรก็ตาม การกำหนดค่า $ADODB_COUNTERRECS ให้เป็น false จะทำให้มีประสิทธิภาพที่ดีกว่า
ตัวแปรนี้จะถูกตรวจสอบทุกครั้งที่มีการเรียกดูข้อมูล ดังนั้นท่านสามารถเลือกได้ว่าจะให้ recordset ตัวใดที่จะถูกนับ


11. Other ADOdb Features
อีกหนึ่ง Feature ของ ADOdb ก็คือ Schema generation ซึ่งช่วยให้ท่านกำหนด schema โดยใช้ XML และนำเข้าไปยังระบบ RDBMS ที่แตกต่างกันออกไปได้
และอีก Feature ก็คือ Performance monitoring and tracing ซึ่งมีคุณสมบัติเด่นก็คือ ความสามารถในการระบุ SQL ที่น่าสงสัย และทำงานช้า โดยมีการอธิบายแนวทางการแก้ไข และระบุ web page ที่ SQL นี้ทำงานอยู่ให้ด้วย


12. Download
ท่านสามารถดาวน์โหลด ADOdb ได้จาก sourceforge ซึ่ง ADOdb มีลิขสิทธิ์แบบ BSD นั่นก็หมายถึง ท่านสามารถใช้ในการพาณิชย์ได้ และอนุญาตให้จัดจำหน่ายได้โดยไม่ต้องมี source code


13. Resources
ท่านสามารถหาข้อมูลได้จากแหล่งอื่นๆ ดังนี้
- Oracle's Hitchhiker Guide to PHP
Oracle FAQ on PHP
- คู่มือ PHP oci8
ADOdb Forums


Copyright (C) 2005 exzilla.net เรียบเรียงจากเอกสารต้นฉบับ Using ADOdb with PHP and Oracle: an advanced tutorial " http://phplens.com/lens/adodb/docs-oracle.htm " โดยคุณ John Lim


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