Saturday, May 2, 2009

ORA_ROWSCN ล๊อคเรคคอร์ดของ Web Application ยังไง ไม่ให้เกิดปัญหา Concurrency

Updated: 1/4/2007

ถ้าคุณเคยเขียน Application ที่เป็น Web base แล้วเคยใช้คำสั่ง SELECT FOR UPDATE คุณอาจจะพบกับปัญหาที่ session ของ web หลุดไปหลังจากที่คุณ SELECT FOR UPDATE ซึ่งเป็นเรื่องที่เกิดขึ้นได้บ่อยๆ ใน Web เทคโนโลยี พอคุณ select ข้อมูลด้วยคำสั่งดังกล่าวเพื่อล๊อค ไม่ให้ใครเข้ามาแก้ไขข้อมูล row เดียวกับของคุณในขณะที่ user กำลังแก้ข้อมูลในหน้า Web ยังไม่ทันที่จะ Submit ก็มีเหตุบางอย่างทำให้ Web session นั้นหลุดไปผลก็คือข้อมูลไม่ได้ถูกอัพเดท แล้ว row นั้นก็จะล๊อคอยู่อย่างนั้นจนกว่า Oracle (หรือตัวคุณเอง) จะมา Kill session นั้นออกไป ซึ่งในระหว่างก่อนจะมีการ Kill session นี้ คนอื่นจะเข้ามาอัพเดท row เดียวกันนี้ไม่ได้เลย
Oracle10g ได้ให้ feature ที่เรียกว่า ORA_ROWSCN ซึ่งเป็น pseudo column ที่จะให้ค่าของ SCN หรือ System Change Number ซึ่งสรุปแบบง่าย ๆ ก็คือหมายเลขที่จะเปลี่ยนไปทุกครั้งที่มีการ commit ทรานแซคชั่น ลองดูจากตัวอย่างดีกว่าครับ

SQL> select ora_rowscn, empno, ename from emp where rownum <> update emp set ename = 'สมชาย' where empno = 7369;
1 row updated.

SQL> commit;
Commit complete.

ถ้าเรา select ข้อมูลขึ้นมาใหม่จะเห็นว่า ORA_ROWSCN เปลี่ยนไป

SQL> select ora_rowscn, empno, ename from emp;
ORA_ROWSCN EMPNO ENAME
---------- ---------- ----------
315968 7369 สมชาย
315951 7499 ALLEN
315951 7521 WARD
315951 7566 JONES

4 rows selected.

จากจุดนี้เองทำให้เราสามารถรู้ได้ว่ามีการเปลี่ยนแปลงข้อมูลไปหลังจากที่เราได้ select ข้อมูลไว้ก่อนหรือเปล่า ซึ่งทำให้เราสามารถเพิ่มเติมเงื่อนไขในการ update ข้อมูลเข้าไป เช่น
SQL> update emp set ename = 'สมโชค' where empno = 7369 and ORA_ROWSCN = 315968;
0 rows updated.

หากว่าก่อนที่เราจะรันคำสั่งข้างบน มี user คนอื่นได้อัพเดทเรคคอร์ดนี้ไปเป็นค่าอื่นแล้ว เราจะพบว่า row นั้นจะไม่ถูกอัพเดทเพราะว่าเลข ORA_ROWSCN ได้เปลี่ยนไปนั่นเอง จากนี้เราอาจจะเช็คว่าถ้าจำนวนของเรคคอร์ดที่ถูกอัพเดทมีค่าเป็น 0 ก็ให้ raise exception ขึ้นมา

SQL> select ora_rowscn, empno, ename from emp where empno = 7369;
ORA_ROWSCN EMPNO ENAME
---------- ---------- ----------
315980 7369 สมชาย

การจะใช้ feature นี้ เราจะต้องสร้างตารางใหม่ โดยเพิ่มคำว่า ROWDEPENDENCIES เข้าไป เนื่องจากโดยปกติ Oracle จะอัพเดท SCN ในระดับ Database Block ข้อมูลที่อยู่ใน Block เดียวกันจะถูกอัพเดท SCN พร้อม ๆ กันซึ่งเราจะไม่รู้ว่า เรคคอร์ดใดที่ถูกอัพเดทบ้าง เมื่อเราสร้างตารางให้เป็นแบบ ROWDEPENDENCIES เรคคอร์ดที่มีการเปลี่ยนแปลงในการ commit แต่ละครั้งจะมี ORA_ROWSCN เดียวกัน

No comments:

Post a Comment