มาเรียนการสร้างเว็บกัน
บริการสอน แนะนำ Adwords , PHP,
MySQL, HTML, FTP, SMF, PHPMyAdmin, Dreamweaver, Oscommerce, Photoshop,
Flash... |
|
|
รับติดตั้ง PHP ให้ติดต่อ ORACLE ได้ ถึงบ้านคุณ เพียง 2,000 บาท เท่านั้น
ติดต่อ MSN, Google Talk ,E-mail: [email protected] ความลึกลับของ Trigger ตอนที่ 1
Oracle
> ความลึกลับของ Trigger ตอนที่ 1
"กลาง
ดึกคืนหนึ่ง... สมชาติยังคงนั่งเขียนโปรแกรมของเขาอยู่
นี่ก็เลยเวลาเลิกงานไปหกชั่วโมงแล้วสินะ
สายตาเขายังคงจ้องเขม็งไปที่จอคอมพิวเตอร์
พยายามที่จะหาเหตุผลว่าทำไมข้อมูลในตารางที่โปรแกรมของ "คนเก่า"
เขาเขียนไว้ จึงมีข้อมูลแปลก ๆ
เก็บไว้ในคอลัมน์ที่ในโปรแกรมก็ไม่ได้แสดงว่าไปอัพเดท
เขาเคยได้ยินว่าที่ตึกแห่งนี้เคยมีโปรแกรมเมอร์คนหนึ่งเสียชีวิตขณะนั่ง
เขียนโปรแกรมในคืนวันหนึ่ง
พอรุ่งเช้าก็มีคนพบเขานอนฟุบอยู่กับคีย์บอร์ดโดยปราศจากลมหายใจแล้ว
หรือว่า....โปรแกรมนี้....มัน....." เรื่องนี้เป็นเรื่องจริงที่เกิดขึ้น
แต่ไม่ได้จริงเพราะโปรแกรมมีผีสิงหรอกครับ
แต่เนื่องมาจากสมชาติไม่รู้จักการทำงานของทริกเกอร์ (Trigger แปลว่า ไก
เช่นไกปืน หรือแปลว่าเหนี่ยวไกก็ได้) มาก่อน หรืออาจจะรู้แต่ไม่ได้เฉลียวใจ
จึงทำให้ต้องนั่งผีหลอกวิญญาณหลอนอยู่อย่างนั้น
ทริกเกอร์
(Trigger) มีลักษณะคล้าย Stored Procedure
ประเภทหนึ่งที่จะถูกกระตุ้นให้ทำงานเมื่อมีการกระทำกับตารางในฐานข้อมูล
การกระทำเช่น การเพิ่ม (Insert), การแก้ไข (Update), หรือการลบ (Delete)
จะมีผลให้ทริกเกอร์ทำงาน
ด้วยคุณสมบัติอันน่าทึ่งอันนี้ทำให้ผู้ที่ได้รู้จักทริกเกอร์ใหม่ ๆ
จะรู้สึกตื่นเต้น และอยากหาทางใดทางหนึ่งในการใช้มันให้ได้
เช่นการแปลงค่าก่อนนำไปใส่ไว้ในคอลัมน์,
ใช้เช็คค่าที่ถูกต้องก่อนนำไปใส่ในคอลัมน์, หรือการสร้างข้อมูล Audit
เป็นต้น ในขณะที่ทริกเกอร์มีคุณสมบัติดี ๆ หลายประการ
แต่ขณะเดียวกันการใช้ทริกเกอร์ก็มีข้อพึงระวังเพื่อไม่ให้เกิดเรื่องลึกลับ
อย่างที่สมชาติเจอ
สาเหตุหลักที่ทำให้ควรหลีกเลี่ยงการใช้ทริกเกอร์ 1.
ทริกเกอร์ทำให้ยุ่งยากในการดูแลในระยะยาว เนื่องจากตัวมันซ่อนอยู่
และรันโดยตัวมันเอง ซึ่งอาจจะเกิดขึ้นเมื่อใดก็ได้
หากถูกกระตุ้นโดยเหตุการณ์ต่าง ๆ ซึ่งคนส่วนใหญ่จะไม่ได้นึกถึง
หรือลืมไปว่ามีทริกเกอร์อยู่ตรงนั้น 2. ทริกเกอร์มักจะถูกนำมาใช้อย่างไม่เหมาะสม โดยเฉพาะสถานการณ์ที่ไม่สามารถ Rollback ได้
ความยุ่งยากในการดูแลในระยะยาว สมมติ
ว่าคุณ กำลังทำงานในโครงงานของคนอื่น
หรือเพราะว่าคุณต้องทำงานที่คนอื่นทำค้างไว้
ถ้าคุณต้องทำการสำรวจตัวโปรแกรม หรืออาจจะเป็น Stored Procedure
ก็อาจจะเป็นวิสัยที่ทำได้
แต่ถ้าคุณพบกับโปรแกรมที่อาศัยทริกเกอร์ที่กระจายอยู่บนตารางต่าง ๆ มากมาย
คุณคงต้องเกาหัวแกร็ก ๆ เพราะไม่รู้จะเริ่มตรงไหนดี?
ทริกเกอร์ทำ
งานแบบเป็นผลข้างเคียงและเป็นเอกเทศ
ไม่ได้อยู่กับโฟลวงานหลักที่คุณสามารถตรวจดูได้ทีละบรรทัด
เมื่อคุณทำการอัพเดทเรคคอร์ดระบบอาจจะตอบกลับว่า 1 Row Proccessed
แต่อาจจะมีสิ่งต่าง ๆ อีก 500 สิ่งเกิดขึ้นจากทริกเกอร์ก็ได้
นอกจากนี้ทริกเกอร์มักไม่ได้รับการจัดทำเป็นเอกสารอย่างเหมาะสม
หรืออาจจะถูกมองข้ามไปเมื่อต้องทำการตรวจสอบตัวโปรแกรม
ลองดูจากตัว อย่างในเว็บไซท์ของ Tom Kyte ดังต่อไปนี้ "เรา
มีปัญหาเกี่ยวกับการอัพ เดทคอลัมน์ (varchar2) ผลการอัพเดทแสดงว่ามี 1,972
แถวที่ถูกอัพเดท (และเราได้ commit แล้ว)
หลังจากนั้นเราดึงข้อมูลมาดูพบว่าคอลัมน์ไม่ได้ถูกอัพเดท
แต่เมื่อเราอัพเดทคอลัมน์อื่นกลับทำให้ค่าในคอลัมน์นี้มีค่าเปลี่ยนแปลงไป"
เหตุการณ์
นี้จบเมื่อผู้ถามพบว่ามีประโยคนี้ :new.name := :new.fname || :new.lname
อยู่ในทริกเกอร์ ซึ่งหมายถึงการที่ระบุให้กำหนดค่าให้กับคอลัมน์ name
ด้วยค่าของ fname || lname (คือคำสั่งให้อัพเดทคอลัมน์ name โดยเอา fname
(ชื่อ) ไปรวมกับ lname (นามสกุล) แล้วนำไปใส่ในคอลัมน์ name) ผู้
ออกแบบโปรแกรมไม่ควรจะใช้คอลัมน์ name
ซึ่งรวมเอาชื่อกับนามสกุลเข้าไว้ด้วยกัน
เพราะเรามีคอลัมน์ชื่อกับคอลัมน์นามสกุลอยู่แล้ว เราสามารถจะใส่ฟังก์ชั่น
Concatenate (||) ไว้ในวิว โดยไม่ต้องนำค่าชื่อ +
นามสกุลไปเก็บไว้ในคอลัมน์จริง ๆ
นอกไปจากนี้ยังมีการเขียนทริกเกอร์อัพเดทคอลัมน์ name
ที่ทำให้เกิดความสับสนขึ้นไปอีก เพราะเมื่อผู้ใช้ระบบต้องการอัพเดทคอลัมน์
name จะทำไม่ได้ถ้าไม่ได้หยุด (Disable) การทำงานของทริกเกอร์ไว้
แต่เมื่ออัพเดทคอลัมน์ fname, lname ข้อมูลในคอลัมน์ name กลับเปลียนไป SQL> create table test_name (fname varchar2(10), lname varchar2(20), name varchar2(30));
Table created
SQL> insert into test_name values ('Somchai','Klaharn','Somchai Klaharn');
1 row inserted
SQL> commit;
Commit complete
SQL> select * from test_name;
FNAME LNAME NAME ---------- -------------------- ------------------------------ Somchai Klaharn Somchai Klaharn
SQL> create or replace trigger upd_testname_trg 2 before update on test_name 3 for each row 4 declare 5 -- local variables here 6 begin 7 :new.name := :new.fname || ' ' || :new.lname; 8 end upd_testname_trg; 9 /
Trigger created
SQL> update test_name set fname = 'Tanakorn',lname = 'Tavornsasnavong';
1 row updated
SQL> select * from test_name;
FNAME LNAME NAME ---------- -------------------- ------------------------------ Tanakorn Tavornsasnavong Tanakorn Tavornsasnavong
SQL> commit;
Commit complete
SQL> update test_name set name = 'Somchai Klaharn';
1 row updated
SQL> commit;
Commit complete
SQL> select * from test_name;
FNAME LNAME NAME ---------- -------------------- ------------------------------ Tanakorn Tavornsasnavong Tanakorn Tavornsasnavong
SQL> alter trigger upd_testname_trg disable;
Trigger altered
SQL> update test_name set name = 'Somchai Klaharn';
1 row updated
SQL> select * from test_name;
FNAME LNAME NAME ---------- -------------------- ------------------------------ Tanakorn Tavornsasnavong Somchai Klaharn ทริกเกอร์
ทำให้การดูแลระบบทำได้ยาก, สับสนง่าย และยังซ่อนตัวเองจากตรวจสอบ
ในการตรวจสอบ Code ทริกเกอร์มักจะถูกลืมจากการตรวจสอบด้วย
อาจจะเนื่องจากคนส่วนใหญ่เห็นว่าทริกเกอร์เป็นส่วนหนึ่งของวัตถุในฐานข้อมูล
(ดังเช่น ตาราง เรามักจะไม่ไปตรวจสอบคำสั่งเช่น CREATE TABLE ตอนตรวจสอบ
Code ในโปรแกรม)
การนำไปใช้อย่างไม่เหมาะสม บ่อยครั้งที่ ผู้สร้างทริกเกอร์อาจจะไม่ได้คิดถึงพฤติกรรมของมันอย่างทั่วถึง ดังเช่น Code ต่อไปนี้ SQL> create trigger send_mail 2 after insert on purchase_order 3 for each row 4 begin 5 utl_mail.send 6 (sender=>'[email protected]', 7 recipients=>'[email protected]', 8 subject=>'New Order '||:new.po_number, 9 message=>'... '); 10 end; 11 / Trigger created.
Code
ข้างต้นถูกต้องในแง่ของไวยกรณ์ และหลังจากที่ Insert
ข้อมูลลงในตารางทริกเกอร์ก็จะทำงานได้อย่างถูกต้อง
แต่มีความผิดพลาดในการนำไปใช้ กล่าวคือถ้าเกิดการ Rollback
เมล์ที่ถูกส่งไปให้กับผู้รับจะไม่สามารถยกเลิกได้ ในการนี้ SMTP (Simple
Mail Transfer Protocol) จะไม่รับรู้ถึงการยกเลิกหรือ Rollback ในฐานข้อมูล
การ Rollback อาจจะเกิดจากสาเหตุอื่น ๆ
ซึ่งอาจจะไม่ได้เกิดจากความจงใจเช่นการ Disconnect
แบบไม่ปกติจากการปิดโปรแกรม SQL*Plus, การเกิดปัญหาเน็ทเวอร์ค เป็นต้น
การใช้ทริกเกอร์กับยูทิลิตี้ต่าง ๆ เช่น UTL_FILE (จัดการไฟล์), UTL_MAIL
(จัดการเมล์), UTL_HTTP (การใช้บริการของ HTTP) ฯลฯ ล้วนประสบปัญหาเดียวกัน
ดังนั้นข้อควรจำประการหนึ่งในการใช้ทริกเกอร์คือ
"อย่าใช้ทริกเกอร์กับระบบงานที่ไม่สามารถ Rollback ได้"
(ยังไม่จบ นะครับ ยังมีตอนต่อไป...ขอขอบคุณที่ให้ความสนใจและโปรดติดตามตอนต่อไปนะครับ) เรียบเรียงจาก "The Trouble with Triggers" โดย Tom Kyte, Oracle Magazine Volume XXII / Number 5 September/October2008, ASK TOM
refer: http://tanakornt.blogspot.com/2010/04/blog-post.html
 |