การตั้งค่าการ จำกัด เวลาสำหรับการทำธุรกรรมใน MySQL / InnoDB


11

ที่เกิดขึ้นจากคำถามที่เกี่ยวข้องนี้ที่ฉันต้องการทราบวิธีการบังคับให้สองธุรกรรมเกิดขึ้นตามลำดับในกรณีที่ไม่สำคัญ (ซึ่งทั้งสองทำงานในแถวเดียวเท่านั้น) ฉันได้รับคำตอบ - ใช้SELECT ... FOR UPDATEเป็นบรรทัดแรกของธุรกรรมทั้งสอง - แต่สิ่งนี้นำไปสู่ปัญหา: หากการทำธุรกรรมครั้งแรกไม่ได้กระทำหรือย้อนกลับธุรกรรมที่สองจะถูกปิดกั้นอย่างไม่มีกำหนด innodb_lock_wait_timeoutตัวแปรกำหนดจำนวนวินาทีหลังจากที่ลูกค้าพยายามที่จะทำให้การทำธุรกรรมที่สองจะได้รับการบอกว่า "ขออภัยลองอีกครั้ง" ... แต่เท่าที่ผมสามารถบอกพวกเขาต้องการจะพยายามอีกครั้งจนกว่ารีบูตเซิร์ฟเวอร์ถัดไป ดังนั้น:

  1. แน่นอนว่าจะต้องมีวิธีการบังคับROLLBACKถ้าธุรกรรมใช้เวลานาน? ฉันต้องหันไปใช้ daemon เพื่อฆ่าธุรกรรมดังกล่าวหรือไม่และถ้าใช่ daemon นั้นจะมีลักษณะอย่างไร
  2. หากการเชื่อมต่อถูกฆ่าตายโดยwait_timeoutหรือinteractive_timeoutmid-transaction ธุรกรรมจะถูกย้อนกลับหรือไม่? มีวิธีทดสอบสิ่งนี้จากคอนโซลหรือไม่?

Clarification : innodb_lock_wait_timeoutตั้งค่าจำนวนวินาทีที่ธุรกรรมจะรอการปลดล็อคก่อนที่จะยอมแพ้ สิ่งที่ฉันต้องการคือวิธีการบังคับให้ล็อคเพื่อปลดล็อค

อัปเดต 1 : ต่อไปนี้เป็นตัวอย่างง่ายๆที่แสดงให้เห็นว่าเหตุใดจึงinnodb_lock_wait_timeoutไม่เพียงพอเพื่อให้แน่ใจว่าการทำธุรกรรมครั้งที่สองไม่ได้ถูกบล็อกโดยรายการแรก:

START TRANSACTION;
SELECT SLEEP(55);
COMMIT;

ด้วยการตั้งค่าเริ่มต้นของinnodb_lock_wait_timeout = 50ธุรกรรมนี้เสร็จสมบูรณ์โดยไม่มีข้อผิดพลาดหลังจาก 55 วินาที และถ้าคุณเพิ่มUPDATEก่อนSLEEPบรรทัดให้เริ่มต้นธุรกรรมครั้งที่สองจากลูกค้ารายอื่นที่พยายามSELECT ... FOR UPDATEแถวเดียวกันนั่นเป็นธุรกรรมที่สองที่หมดเวลาไม่ใช่รายการที่หลับไป

สิ่งที่ฉันกำลังมองหาคือวิธีที่จะยุติการนอนหลับพักผ่อนของธุรกรรมนี้

อัปเดต 2 : เพื่อตอบสนองต่อข้อกังวลของ hobodave เกี่ยวกับความเป็นจริงของตัวอย่างด้านบนนี่คือสถานการณ์จำลองทางเลือก: DBA เชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้งานจริงและทำงานอยู่

START TRANSACTION
SELECT ... FOR UPDATE

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


คุณเพิ่งอัปเดตคำถามเพื่อขัดแย้งกับคำถามเริ่มต้นอย่างสมบูรณ์ คุณระบุด้วยตัวหนา "ถ้าการทำธุรกรรมครั้งแรกไม่เคยกระทำหรือย้อนกลับการทำธุรกรรมครั้งที่สองจะถูกบล็อกไปเรื่อย ๆ " คุณพิสูจน์หักล้างสิ่งนี้ด้วยการอัปเดตล่าสุดของคุณ: "นี่เป็นธุรกรรมครั้งที่สองที่หมดเวลาไม่ใช่รายการที่หลับไป" -- อย่างจริงจัง?!
hobodave

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

@ เทรเวอร์: ถ้อยคำของคุณชัดเจนอย่างสมบูรณ์ คุณได้อัปเดตคำถามของคุณเพื่อถามสิ่งที่แตกต่างอย่างสิ้นเชิงซึ่งเป็นรูปแบบที่ไม่ดีอย่างยิ่ง
hobodave

คำถามนั้นเหมือนกันเสมอ: เป็นปัญหาที่การทำธุรกรรมครั้งที่สองถูกปิดกั้นโดยไม่มีกำหนดเมื่อไม่มีการทำธุรกรรมครั้งแรกหรือย้อนกลับ ฉันต้องการบังคับให้ROLLBACKทำธุรกรรมครั้งแรกหากใช้เวลานานกว่าnวินาทีเพื่อให้เสร็จสมบูรณ์ มีวิธีการทำเช่นนั้น?
เทรเวอร์เบิร์นแฮม

1
@TrevorBurnham ฉันยังสงสัยว่าทำไมMYSQLไม่มีการกำหนดค่าเพื่อป้องกันสถานการณ์นี้ เพราะมันไม่เป็นที่ยอมรับของเซิร์ฟเวอร์แฮงค์เนื่องจากลูกค้าขาดความรับผิดชอบ ฉันไม่พบปัญหาในการเข้าใจคำถามของคุณ แต่อย่างใดมันเกี่ยวข้องกันมาก
Dinoop paloli

คำตอบ:


10

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

ทางออกหนึ่งถ้าคุณเต็มใจที่จะฆ่าการเชื่อมต่อทั้งหมดคือการตั้งค่า wait_timeout / interactive_timeout ดู/programming/9936699/mysql-rollback-on-transaction-with-lost-disconnected-connection


3

เนื่องจากคำถามของคุณถูกถามที่นี่ใน ServerFault มันมีเหตุผลที่จะสมมติว่าคุณกำลังมองหาวิธีการแก้ปัญหา MySQL สำหรับปัญหา MySQL โดยเฉพาะอย่างยิ่งในขอบเขตของความรู้ที่ผู้ดูแลระบบและ / หรือ DBA จะมีความเชี่ยวชาญมาดังต่อไปนี้ ส่วนที่อยู่คำถามของคุณ:

หากการทำธุรกรรมครั้งแรกไม่เคยกระทำหรือย้อนกลับธุรกรรมที่สองจะถูกบล็อกโดยไม่มีกำหนด

ไม่มันจะไม่ innodb_lock_wait_timeoutฉันคิดว่าคุณไม่เข้าใจ มันทำสิ่งที่คุณต้องการ

มันจะกลับมาพร้อมกับข้อผิดพลาดตามที่ระบุไว้ในคู่มือ:

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  • ตามคำนิยามนี้ไม่ได้ไม่แน่นอน หากแอปพลิเคชันของคุณเชื่อมต่อใหม่และบล็อกซ้ำ ๆ แสดงว่าแอปพลิเคชันของคุณ "บล็อกอย่างไม่มีกำหนด" ไม่ใช่ธุรกรรม ธุรกรรมครั้งที่สองจะปิดกั้นอย่างแน่นอนเป็นinnodb_lock_wait_timeoutวินาที

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

หากคุณต้องการย้อนกลับอัตโนมัตินั่นจะอธิบายไว้ในคู่มือ:

ธุรกรรมปัจจุบันไม่ย้อนกลับ (หากต้องการให้ธุรกรรมทั้งหมดย้อนกลับให้เริ่มต้นเซิร์ฟเวอร์ด้วย--innodb_rollback_on_timeoutตัวเลือก


RE: การอัปเดตและความคิดเห็นมากมายของคุณ

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

อย่างไรก็ตามฉันสามารถตอบคำถามนั้นได้เช่นกัน โปรโตคอล MySQL ไม่มี "ไทม์เอาต์ของแบบสอบถาม" ซึ่งหมายความว่าคุณไม่สามารถหมดเวลาธุรกรรมที่ถูกบล็อกครั้งแรก คุณต้องรอจนกว่าจะเสร็จสิ้นหรือฆ่าเซสชัน เมื่อเซสชันถูกฆ่าเซิร์ฟเวอร์จะย้อนกลับธุรกรรมโดยอัตโนมัติ

ทางเลือกอื่นเท่านั้นที่จะใช้หรือเขียนไลบรารี mysql ซึ่งใช้ I / O ที่ไม่มีการปิดกั้นซึ่งจะอนุญาตให้แอปพลิเคชันของคุณฆ่าเธรด / ฟอร์กสร้างคิวรีหลังจาก N วินาที การใช้งานและการใช้งานไลบรารีดังกล่าวอยู่นอกเหนือขอบเขตของ ServerFault นี่เป็นคำถามที่เหมาะสมสำหรับStackOverflow

ประการที่สองคุณได้ระบุสิ่งต่อไปนี้ในความคิดเห็นของคุณ:

จริง ๆ แล้วฉันเป็นห่วงคำถามของฉันด้วยสถานการณ์ที่แอพไคลเอ็นต์แฮงค์ (พูดถูกติดอยู่ในวงวนไม่สิ้นสุด) ในระหว่างการทำธุรกรรมมากกว่าในกรณีที่การทำธุรกรรมใช้เวลานานในตอนท้ายของ MySQL

สิ่งนี้ไม่ปรากฏชัดเจนในคำถามต้นฉบับของคุณและยังไม่เป็นเช่นนั้น สิ่งนี้สามารถแยกแยะได้หลังจากที่คุณแบ่งปันชิ้นอาหารอันโอชะที่สำคัญมากกว่านี้ในความคิดเห็น

หากนี่เป็นปัญหาที่คุณพยายามแก้ไขจริง ๆ แล้วฉันเกรงว่าคุณจะถามในฟอรัมที่ไม่ถูกต้อง คุณได้อธิบายถึงปัญหาการเขียนโปรแกรมระดับแอปพลิเคชันซึ่งต้องการโซลูชันการเขียนโปรแกรมซึ่ง MySQL ไม่สามารถให้บริการได้และอยู่นอกขอบเขตของชุมชนนี้ คำตอบล่าสุดของคุณตอบคำถาม "ฉันจะป้องกันโปรแกรม Ruby จากการวนซ้ำไม่สิ้นสุดได้อย่างไร" คำถามที่เป็นปิดหัวข้อชุมชนนี้และควรจะถามในStackOverflow


ขออภัยในขณะที่เป็นจริงเมื่อธุรกรรมกำลังรอการล็อก (เป็นชื่อและเอกสารinnodb_lock_wait_timeoutแนะนำ) มันไม่เป็นเช่นนั้นในสถานการณ์ที่ฉันโพสต์: ที่ลูกค้าค้างหรือหยุดทำงานก่อนที่จะได้รับการเปลี่ยนแปลงที่จะทำCOMMITหรือROLLBACK.
เทรเวอร์เบิร์นแฮม

@ เทรเวอร์: คุณผิด นี่เป็นเรื่องเล็กน้อยที่จะทดสอบในตอนท้ายของคุณ ฉันเพิ่งทดสอบมันในตอนท้ายของฉัน โปรดนำ downvote ของคุณกลับมา
hobodave

@hobo เพียงเพราะสิทธิของคุณไม่ได้หมายความว่าเขาจะต้องชอบมัน
Chris S

คริสคุณช่วยอธิบายว่าเขาพูดถูกมั้ย ธุรกรรมที่สองจะเกิดขึ้นได้อย่างไรหากไม่มีCOMMITหรือROLLBACKมีการส่งข้อความเพื่อแก้ไขธุรกรรมแรก Hobodave อาจจะมีประโยชน์หากคุณแสดงรหัสทดสอบ
เทรเวอร์เบิร์นแฮม

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

1

ในสถานการณ์ที่คล้ายกันทีมของฉันตัดสินใจใช้ pt-kill ( https://www.percona.com/doc/percona-toolkit/2.1/pt-kill.html ) มันสามารถรายงานหรือฆ่าแบบสอบถามที่ (เหนือสิ่งอื่น) กำลังทำงานนานเกินไป เป็นไปได้ที่จะรันใน cron ทุก ๆ X นาที

ปัญหาคือว่าแบบสอบถามที่มีเวลาดำเนินการที่ยาวนานอย่างไม่คาดคิด (เช่นไม่ จำกัด ) ล็อกโพรซีเดอร์สำรองที่พยายามล้างตารางด้วยล็อกการอ่านซึ่งจะล็อกคิวรีอื่น ๆ ทั้งหมดที่ "รอตารางเพื่อล้างข้อมูล" ซึ่งไม่เคยหมดเวลา เพราะพวกเขาไม่รอการล็อคซึ่งส่งผลให้ไม่มีข้อผิดพลาดในแอปพลิเคชันซึ่งท้ายที่สุดก็ส่งผลให้ไม่มีการแจ้งเตือนให้ผู้ดูแลระบบและแอปพลิเคชันหยุดทำงาน

เห็นได้ชัดว่าการแก้ไขเพื่อแก้ไขแบบสอบถามเริ่มต้น แต่เพื่อหลีกเลี่ยงสถานการณ์ที่เกิดขึ้นโดยบังเอิญในอนาคตมันจะดีถ้ามันเป็นไปได้โดยอัตโนมัติฆ่า (หรือรายงานบน) ธุรกรรม / แบบสอบถามที่นานกว่าเวลาที่เฉพาะเจาะจง ผู้เขียนคำถามคนไหนที่ดูเหมือนจะถาม สามารถทำได้ด้วย pt-kill


0

วิธีแก้ปัญหาอย่างง่ายคือการมีขั้นตอนการจัดเก็บเพื่อฆ่าแบบสอบถามที่ใช้เวลามากกว่าเวลาที่คุณต้องการtimeoutและใช้innodb_rollback_on_timeoutตัวเลือกพร้อมกับมัน


-2

หลังจาก Googling ไประยะหนึ่งดูเหมือนว่าจะไม่มีวิธีโดยตรงในการกำหนดเวลาต่อธุรกรรม นี่เป็นทางออกที่ดีที่สุดที่ฉันสามารถหาได้:

คำสั่ง

SHOW PROCESSLIST;

ให้ตารางกับคำสั่งทั้งหมดที่กำลังเรียกใช้และเวลา (เป็นวินาที) ตั้งแต่เริ่มต้น เมื่อลูกค้าหยุดให้คำสั่งแล้วพวกเขาก็อธิบายว่าให้Sleepคำสั่งโดยมีTimeคอลัมน์เป็นจำนวนวินาทีนับตั้งแต่คำสั่งสุดท้ายของพวกเขาเสร็จสมบูรณ์ ดังนั้นคุณสามารถเข้าไปด้วยตนเองและKILLทุกสิ่งที่มีTimeค่ามากกว่าพูด 5 วินาทีถ้าคุณมั่นใจว่าไม่มีการสืบค้นใดที่ควรใช้เวลามากกว่า 5 วินาทีในฐานข้อมูลของคุณ ตัวอย่างเช่นหากกระบวนการที่มี id 3 มีค่าเป็น 12 ในTimeคอลัมน์คุณสามารถทำได้

KILL 3;

เอกสารสำหรับไวยากรณ์ KILLแสดงให้เห็นว่าการทำธุรกรรมที่ดำเนินการโดยเธรดที่มีรหัสนั้นจะถูกย้อนกลับ (แม้ว่าฉันยังไม่ได้ทดสอบสิ่งนี้ดังนั้นควรระมัดระวัง)

แต่จะทำให้เป็นแบบอัตโนมัติและฆ่าสคริปต์การทำงานล่วงเวลาทั้งหมดทุก 5 วินาทีได้อย่างไร ความคิดเห็นแรกในหน้าเดียวกันนั้นให้คำแนะนำแก่เรา แต่รหัสนั้นอยู่ใน PHP ดูเหมือนว่าเราไม่สามารถดำเนินการSELECTต่อSHOW PROCESSLISTจากภายในไคลเอนต์ MySQL ถึงกระนั้นถ้าเรามี PHP daemon ที่เราเรียกใช้ทุก$MAX_TIMEวินาทีมันอาจมีลักษณะดังนี้:

$result = mysql_query("SHOW FULL PROCESSLIST");
while ($row=mysql_fetch_array($result)) {
  $process_id=$row["Id"];
    if ($row["Time"] > $MAX_TIME) {
      $sql="KILL $process_id";
      mysql_query($sql);
  }
}

โปรดทราบว่านี่จะมีผลข้างเคียงของการบังคับให้การเชื่อมต่อไคลเอนต์ที่ไม่ได้ใช้งานทั้งหมดทำการเชื่อมต่อใหม่ไม่ใช่แค่การทำงานที่ผิดปกติ

หากใครมีคำตอบที่ดีกว่าฉันชอบที่จะได้ยินมัน

แก้ไข:มีความเสี่ยงอย่างร้ายแรงอย่างน้อยหนึ่งอย่างในการใช้KILLวิธีนี้ สมมติว่าคุณใช้สคริปต์ด้านบนKILLทุกการเชื่อมต่อที่ไม่ได้ใช้งานเป็นเวลา 10 วินาที หลังจากการเชื่อมต่อไม่ได้ใช้งานเป็นเวลา 10 วินาที แต่ก่อนที่KILLจะมีการออกผู้ใช้ที่การเชื่อมต่อจะถูกฆ่าจะออกSTART TRANSACTIONคำสั่ง พวกเขากำลังKILLเอ็ดแล้ว พวกเขาส่งแล้วคิดสองครั้งปัญหาUPDATE ROLLBACKอย่างไรก็ตามเนื่องจากการKILLย้อนกลับทรานแซกชันดั้งเดิมของพวกเขาการอัพเดทจึงผ่านไปทันทีและไม่สามารถย้อนกลับได้! ดูโพสต์นี้สำหรับกรณีทดสอบ


2
ความคิดเห็นนี้มีไว้สำหรับผู้อ่านในอนาคตของคำตอบนี้ กรุณาอย่าทำเช่นนี้แม้ว่ามันจะเป็นคำตอบที่ยอมรับ
hobodave

ตกลงแทนที่จะเป็น downvoting และออกความคิดเห็นที่หยาบคายแล้วจะอธิบายได้อย่างไรว่าทำไมนี่จึงเป็นความคิดที่ไม่ดี บุคคลที่โพสต์สคริปต์ PHP ดั้งเดิมบอกว่าไม่ให้เซิร์ฟเวอร์หยุดการทำงาน หากมีวิธีที่ดีกว่าในการบรรลุเป้าหมายเดียวกันแสดงให้ฉันดู
เทรเวอร์เบิร์นแฮม

6
ความคิดเห็นที่ไม่ได้เย้ยหยัน มันเป็นคำเตือนสำหรับผู้อ่านในอนาคตที่จะไม่พยายามใช้ "วิธีแก้ปัญหา" ของคุณ การฆ่าธุรกรรมที่ใช้เวลานานโดยอัตโนมัติเป็นความคิดที่น่ากลัวเพียงฝ่ายเดียว มันควรไม่เคยทำได้ นั่นคือคำอธิบาย เซสชันการฆ่าควรเป็นข้อยกเว้นไม่ใช่บรรทัดฐาน สาเหตุของปัญหาประดิษฐ์ของคุณเป็นข้อผิดพลาดของผู้ใช้ คุณไม่ได้สร้างโซลูชันทางเทคนิคสำหรับ DBA ที่ล็อคแถวแล้ว "เดิน" คุณยิงพวกเขา
hobodave

-2

ตามที่ hobodave แนะนำในการแสดงความคิดเห็นจึงมีความเป็นไปได้ที่ลูกค้าบางราย (แม้ว่าจะไม่ใช่mysqlยูทิลิตี้บรรทัดคำสั่ง) แต่ก็สามารถตั้งเวลาได้สำหรับธุรกรรม นี่คือการสาธิตโดยใช้ ActiveRecord ใน Ruby:

require 'rubygems'
require 'timeout'
require 'active_record'

Timeout::timeout(5) {
  Foo.transaction do
    Foo.create(:name => 'Bar')
    sleep 10
  end
}

ในตัวอย่างนี้ครั้งที่ทำรายการออกมาหลังจาก 5 วินาทีและได้รับรีดอัตโนมัติกลับ ( อัปเดตเพื่อตอบสนองต่อความคิดเห็นของ hobodave:หากฐานข้อมูลใช้เวลานานกว่า 5 วินาทีในการตอบสนองธุรกรรมจะถูกย้อนกลับทันทีที่ทำ - ไม่ช้ากว่านี้) หากคุณต้องการให้แน่ใจว่าธุรกรรมทั้งหมดของคุณหมดเวลาในไม่nกี่วินาที คุณสามารถสร้าง wrapper รอบ ๆ ActiveRecord ฉันเดาว่านี่จะใช้กับไลบรารียอดนิยมใน Java, .NET, Python และอื่น ๆ แต่ฉันยังไม่ได้ทดสอบ (ถ้าคุณมีโปรดโพสต์ความคิดเห็นในคำตอบนี้)

ธุรกรรมใน ActiveRecord ยังมีข้อดีของความปลอดภัยหากมีการKILLออกซึ่งแตกต่างจากธุรกรรมที่ทำจากบรรทัดคำสั่ง ดู/dba/1561/mysql-client-believes-theyre-in-a-transaction-gets-killed-wreaks-havoc

ดูเหมือนจะเป็นไปไม่ได้ที่จะบังคับใช้เวลาการทำธุรกรรมสูงสุดในฝั่งเซิร์ฟเวอร์ยกเว้นผ่านสคริปต์เช่นเดียวกับที่ฉันโพสต์ในคำตอบอื่น ๆ ของฉัน


คุณมองข้ามว่า ActiveRecord ใช้ I / O แบบซิงโครนัส สคริปต์ทั้งหมดที่ทำงานนั้นขัดจังหวะคำสั่ง Ruby sleep หากFoo.createคำสั่งของคุณบล็อกเป็นเวลา 5 นาทีการหมดเวลาจะไม่ฆ่า สิ่งนี้ไม่สามารถใช้ร่วมกับตัวอย่างที่ให้ไว้ในคำถามของคุณ A SELECT ... FOR UPDATEสามารถบล็อกได้อย่างง่ายดายเป็นเวลานานเช่นเดียวกับแบบสอบถามอื่น ๆ
hobodave

ควรสังเกตว่าไลบรารีไคลเอนต์ mysql เกือบทั้งหมดใช้การบล็อก I / O ดังนั้นคำแนะนำในคำตอบของฉันที่คุณจะต้องใช้หรือเขียนของคุณเองที่ใช้ I / O ที่ไม่บล็อก นี่คือการสาธิตง่ายๆเกี่ยวกับการหมดเวลาที่ไร้ประโยชน์: gist.github.com/856100
hobodave

จริง ๆ แล้วฉันเป็นห่วงคำถามของฉันด้วยสถานการณ์ที่แอพไคลเอ็นต์แฮงค์ (พูดถูกติดอยู่ในวงวนไม่สิ้นสุด) ในระหว่างการทำธุรกรรมมากกว่าในกรณีที่การทำธุรกรรมใช้เวลานานในตอนท้ายของ MySQL แต่ขอบคุณที่เป็นจุดที่ดี ฉันได้อัปเดตคำถามเพื่อให้ทราบแล้ว)
Trevor Burnham

ฉันไม่สามารถทำซ้ำผลลัพธ์ที่คุณอ้างสิทธิ์ได้ ฉันอัปเดตส่วนสำคัญที่จะใช้ActiveRecord::Base#find_by_sql: gist.github.com/856100อีกครั้งนี่เป็นเพราะ AR ใช้การบล็อก I / O
hobodave

@hobodave ใช่การแก้ไขนั้นผิดพลาดและได้รับการแก้ไขแล้ว มีความชัดเจน: timeoutวิธีการจะย้อนกลับการทำธุรกรรม แต่ไม่จนกว่าฐานข้อมูล MySQL ตอบสนองต่อการค้นหา ดังนั้นtimeoutวิธีนี้จึงเหมาะสำหรับการป้องกันธุรกรรมที่ยาวในฝั่งไคลเอ็นต์หรือธุรกรรมที่ยาวซึ่งประกอบด้วยแบบสอบถามที่ค่อนข้างสั้นหลายรายการ แต่ไม่ใช่สำหรับธุรกรรมที่ยาวซึ่งแบบสอบถามเดียวคือผู้ร้าย
เทรเวอร์เบิร์นแฮม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.