ช่วงที่ผ่านมาผมนั่งทำโปรแกรมกึ่งๆ ERP อยู่ ตั้งแต่ฐานลูกค้า ใบเสนอราคา ควบคุมการผลิต จัดส่งสินค้า จนถึงการรับจ่ายเงิน

ระหว่างที่กำลังทำส่วนของ คลังสินค้า ผมก็ได้ตัดสินใจพลาดไปนิดนึงตรงที่ว่า คนคีย์รับสินค้า จ่ายสินค้า เป็นคนๆเดียวกัน ถึงหลายๆคน มาคีย์พร้อมกัน ก็ไม่น่ามีปัญหาเรื่องของ concurrency อะไร ปรากฏว่าระบบผมโดน abused

user ทั้งหลายของผมสามารถเบิกสินค้าได้มากกว่าจำนวนที่มีอยู่ อะไรมันจะเสี้ยววินาทีขนาดนั้น

บางทีก็คิดว่าเราควรจะสร้างตารางสรุปยอดเป็น View มาครอบตารางเบิกจ่าย อีกทีนึง แต่คิดไปคิดมา ระบบคงต้องใช้ไปอีกเป็นสิบปี ซึ่งก็น่าจะคิดว่าคิดถูกนะ ตอนนี้ถ้าสร้าง view จากตารางเบิกจ่ายก็ใช้เวลาประมาณ 1 วิ กับสินค้าหมื่นกว่ารายการ รับจ่ายอีกเกือบ 6 หมื่นรายการในเวลาไม่ถึงปี (และมันจะโตขึ้นเรื่อยๆ เพราะพื้นฐานของบริษัทเป็น user-customized product)

ก็โอเคเราพลาดไปแล้ว แต่มาเริ่มกันใหม่ ปัดฝุ่นวิชา Database 101 เรื่องของ Concurrency

ปัญหาของ code ที่เขียนไปคือ เป็นลักษณะของ Select A row-> update A row นั่นก็คืออ่านมาก่อน ว่าจำนวนคงคลังเป็นเท่าไหร่ แล้วก็อัพเดทจำนวนคงคลังใหม่ (ใน transaction เดียวกัน) เมื่อมีการรับหรือจ่าย  ซึ่งมันมีปัญหาแน่นอนในเรื่องของ consistency/integrity ของข้อมูล ถ้าในระหว่างที่ session แรกยังอัพเดทไม่เสร็จ แล้วมี session ที่สองมาอ่านค่า A row เพื่อเอาไปคำนวณ

วิธีแก้ปัญหาก้คือ

Select 1 from inventory where id = 1234 for update

คำสั่ง for update จะทำการ lock row ที่เรากำหนดไว้ใน where clause โดย session อื่นจะไม่สามารถมาอ่านค่า row นี้ได้จนกว่าเราจะ commit/rollback transaction หลังจากนั้นเราก็สามารถทำการ execute  select แล้ว update statement ได้เลย

เพื่อความมั่นใจอีก เลยเอา logic ทั้งหมดนี้ไปไว้ใน Store Procedure อีกที จะได้ไม่ต้องมายุ่งอะไรกับมันอีก

แต่ปัญหาข้างบน ไม่ได้แก้ปัญหา ในเชิง application ที่ user อาจจะต้องการอัพเดทจำนวน stock คงคลังสุทธิ แต่ในระหว่างนั้นมีคนมากดเบิกสินค้าออกไปก่อน ทำให้ข้อมูล stock ก่อนหน้าไม่สะท้อนความเป็นจริง ปัญหานี้ก็น่าจะสามารถแก้ได้ด้วยระบบการทำงานขององค์กร หรือจะให้ทำในระบบ ERP ก็น่าาจะได้เช่นกัน