วิธีสอบถามและเพิ่มมูลค่า (ตัวนับ) ในวิธีที่ปลอดภัยต่อเธรด (หลีกเลี่ยงสภาพการแข่งขัน)


10

ในตารางที่แต่ละแถวมีเคาน์เตอร์ (เพียงค่าจำนวนเต็ม) ผมจำเป็นต้องได้รับค่าปัจจุบันและเพิ่มขึ้นในเวลาเดียวกัน

อย่างมีประสิทธิภาพฉันต้องการทำสิ่งนี้:

SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123

แต่การทำเช่นนี้เนื่องจากเคียวรีสองรายการนั้นไม่ปลอดภัยสำหรับเธรด: หลายกระบวนการที่ทำสิ่งเดียวกัน (ในแถวเดียวกัน) อาจได้รับค่าตัวนับเดียวกัน ฉันต้องการให้ทุกอย่างไม่ซ้ำกันดังนั้นแต่ละกระบวนการจะได้รับมูลค่าปัจจุบันตามจริงและเพิ่มขึ้นทีละรายการ

ฉันสามารถนึกถึงการก่อสร้างที่ฉันใช้การล็อกแบบแมนนวลต่อแถว แต่ฉันสงสัยว่าจะมีวิธีที่ง่ายกว่านี้หรือไม่


ใช้การทำธุรกรรมอาจ?
ypercubeᵀᴹ

คำตอบ:


15

งบปรับปรุงทำงานได้อย่างสมบูรณ์แบบโดยไม่ต้องเลือกมาก่อน! เนื่องจากคำสั่งเดียวปลอดภัยตามคำนิยามแม้แต่การสืบค้น UPDATE สองครั้งในเวลาเดียวกันจะส่งผลให้แถวเพิ่มขึ้นสองครั้ง

หากคุณต้องการเลือกค่าสำหรับสคริปต์ PHP ของคุณให้ทำบางสิ่งกับมันและในภายหลังต้องการอัปเดตค่าตัวนับที่แน่นอนคุณสามารถทำสิ่งต่อไปนี้:

BEGIN;
SELECT `counter` FROM `table` WHERE `id` = 123 FOR UPDATE;
UPDATE `table` SET `counter` = `counter`+1 WHERE `id` = 123;
COMMIT;

นี่เป็นการเริ่มธุรกรรมใหม่จากนั้นเลือกแถวที่คุณต้องการอัปเดตและล็อคพวกเขาโดยเฉพาะ จากนั้นคุณสามารถอัปเดตอย่างปลอดภัยโดยไม่ต้องกังวลว่าลูกค้ารายอื่นจะเปลี่ยนเนื้อหาหรือแม้แต่เข้าถึงแถวที่ถูกล็อค ในที่สุดคุณต้องยอมรับการเปลี่ยนแปลงของคุณ

นอกจากนี้คุณควรอ่านสิ่งที่เกี่ยวกับระดับความเหงา คุณอาจไม่ต้องการค่าเช่นเดียวREAD UNCOMMITTEDกับระดับการแยก ทุกอย่างอื่นควรจะดีสำหรับกรณีการใช้งานนี้


ฉันอ่านในที่อื่นว่าUPDATE table SET counter = counter + 1อะตอมมีค่าเพียงพอหรือไม่ คุณยังต้องการงบการทำธุรกรรมโดยรอบอยู่หรือไม่?
CMCDragonkai

@CMCDragonkai ข้อความค้นหาของคุณเพียงอย่างเดียวคืออะตอมมิก แต่ถ้าคุณเลือกค่าก่อนหน้าและไม่ได้ใช้FOR UPDATEและธุรกรรมค่าที่คุณเลือกอาจแตกต่างจากที่ใช้ในการสืบค้นอัปเดต ชุดค่าผสมของแบบสอบถามจะล็อกแถวทันทีที่เลือกค่าดังนั้นจึงมั่นใจได้ว่าค่าตัวนับที่แน่นอนนี้จะถูกใช้ในแบบสอบถามแบบใช้ปรับปรุงข้อมูล
GhostGambler

ตกลง แต่มันก็จำเป็นเท่านั้นถ้าฉันทำงานอื่นนอกเหนือจากการเพิ่มที่ถูกต้อง? ตามที่กล่าวมาแบบสอบถามเคียวรีอะตอมเดี่ยวที่ดีพอถ้านั่นคือทั้งหมดที่ฉันต้องการทำ?
CMCDragonkai

1
@CMCDragonkai หากคุณไม่เรียกใช้แบบสอบถามอื่นที่แตะคอลัมน์แสดงว่าคุณดี
GhostGambler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.