1. วิธีการออก
เดิมทีฉันคิดว่ากระบวนการจะออกทันทีหลังจากดำเนินการเมธอด Exit แต่ฉันเปลี่ยนใจหลังจากสร้างตัวอย่างเพื่อทดสอบแล้ว โปรดดูสิ่งนี้
ตัวอย่างเช่น ในที่สุดแฟล็กก็ถูกกำหนดให้เป็นค่า 'C'
================================================== ==============================================
var
ธง: สตริง;
เริ่ม
พยายาม
ธง := 'A';
ออก;
ธง := 'B';
ในที่สุด
ธง := 'C';
จบ;
ธง := 'D';
จบ;
================================================== ==============================================
การวิเคราะห์: ไม่ว่า try clause จะจบลงอย่างไร สุดท้าย clause จะถูกดำเนินการเสมอ (ขอบคุณชาวเน็ต ylmg)
2. ปัญหาเล็กๆ น้อยๆ ที่ทำให้ทั้งระบบต้องหยุดชะงัก
ในการออกแบบระบบฐานข้อมูล การดำเนินการธุรกรรมมักใช้เพื่อให้มั่นใจในความสมบูรณ์ของข้อมูล อย่างไรก็ตาม การออกแบบที่ไม่เหมาะสมอาจส่งผลกระทบค่อนข้างมาก ตัวอย่างต่อไปนี้แสดงให้เห็นว่าถึงแม้จะมีการรับประกันความสมบูรณ์ของข้อมูล แต่ระบบอาจหยุดทำงานโดยสิ้นเชิง:
================================================== ==============================================
AdoConnection1.BeginTrans;
พยายาม
-
if application.MessageBox('คุณแน่ใจที่จะลบ?', 'คำถาม', MB_YESNO+MB_ICONQUESTION)<>IDใช่แล้ว //(1)
เริ่ม
-
จบ;
Application.MessageBox('การดำเนินการล้มเหลว', 'คำเตือน', MB_OK); //(2)
AdoConnection1.CommitTrans;
ยกเว้น
Application.MessageBox('การดำเนินการล้มเหลว', 'คำเตือน', MB_OK); //(3)
AdoConnection1.ย้อนกลับทรานส์;
จบ;
================================================== ==============================================
วิเคราะห์: ปัญหาในโค้ดข้างต้นทั้งหมดเกิดจาก Application.MessageBox ใน (1), (2) และ (3) แต่ไม่ใช่ Application.MessageBox เองที่เป็นสาเหตุของปัญหา แต่มันค้างโปรแกรมและจำเป็นต้อง การแทรกแซงของผู้ใช้ จากนั้นดำเนินการต่อไป หากผู้ใช้ออกจากคอมพิวเตอร์ในเวลานี้ หรือไม่ยืนยันการทำงานของกล่องโต้ตอบเหล่านี้ อาจเป็นไปได้ว่าทั้งระบบอยู่ในสถานะรอเนื่องจากธุรกรรมนี้ไม่ได้ สิ้นสุดแล้ว
เพื่อหลีกเลี่ยงปัญหานี้ มีสองหลักการ:
(1) หลังจากเริ่มต้นธุรกรรม โปรแกรมสามารถสิ้นสุดธุรกรรมโดยอัตโนมัติโดยไม่ต้องมีการแทรกแซงจากผู้ใช้
(2) ดำเนินการสั้นที่สุดในการทำธุรกรรม
3. ลอง...ยกเว้น...จบโครงสร้าง
ต่อไปนี้เป็นตัวอย่างเพื่อแสดงโครงสร้าง try หรือตัวอย่างการใช้ธุรกรรม:
รหัสที่เป็นปัญหา:
================================================== ==============================================
พยายาม
-
AdoConnection1.BeginTrans;
-
AdoConnection1.CommitTrans;
ยกเว้น
AdoConnection1.ย้อนกลับทรานส์;
จบ;
================================================== ==============================================
การวิเคราะห์: หากมีข้อยกเว้นเกิดขึ้นในโค้ด AdoConnection1.BeginTrans หลังจากลองแล้ว ระบบจะข้ามไปที่ AdoConnection1.RollbackTrans เพื่อดำเนินการ แต่ AdoConnection1 ไม่ได้เริ่มธุรกรรมเนื่องจากมีข้อผิดพลาด ดังนั้นจึงเกิดข้อผิดพลาดระหว่างการดำเนินการ AdoConnection1.RollbackTrans
รหัสที่ถูกต้อง: ============================================== = =================================================
AdoConnection1.BeginTrans;
พยายาม
-
-
AdoConnection1.CommitTrans;
ยกเว้น
AdoConnection1.ย้อนกลับทรานส์;
จบ;
================================================== ==============================================
กล่าวโดยสรุป โครงสร้างของ try ถูกใช้เพื่อป้องกันการดำเนินการที่ผิดปกติ หากมีข้อยกเว้นเกิดขึ้นระหว่าง try...ยกเว้น การดำเนินการระหว่างยกเว้น...end จะถูกดำเนินการ เมื่อออกแบบคำสั่ง try คุณต้องใส่ใจกับความเป็นเหตุเป็นผล ของสถาปัตยกรรม
4. ฉ้อโกงคุ้มครองกิจการของตนเอง
เมื่อสร้างซอฟต์แวร์แอปพลิเคชันฐานข้อมูล เรามักจะประสบปัญหาต่อไปนี้: ตัดสินข้อมูลต้นฉบับแล้วทำการแก้ไขที่เกี่ยวข้อง ปัญหานี้ดูเหมือนค่อนข้างง่าย แต่ถ้าคุณพิจารณาว่ามีบุคคลอื่นบนเครือข่ายที่ใช้ระบบเดียวกัน คุณต้องพิจารณาถึงความเป็นไปได้ของการเปลี่ยนแปลงโดยไม่ตั้งใจ เพื่อนร่วมงานของฉันประมาท แม้ว่าเขาจะพิจารณาถึงปัญหาที่มีผู้ใช้หลายรายหลังจากที่ฉันแจ้ง แต่เขาก็ยังคงเขียนโค้ดที่เป็นปัญหา:
================================================== ==============================================
var
adsTemp: TAdoDataSet;
isOk: บูลีน;
เริ่ม
adsTemp := TAdoDataSet.Create(ตนเอง);
พยายาม
adsTemp.Connection := AdoConnection1;
adsTemp.CommandText := 'เลือก fid, fnumber จาก tb1 โดยที่ fid=120';
adsTemp.เปิด;
isOk := adsTemp.FieldByName('fnumber').AsInteger>100;
ในที่สุด
adsTemp.ฟรี;
จบ;
ถ้าไม่ก็ไม่เป็นไร
ออก;
AdoConnection1.BeginTrans;
พยายาม
AdoConnection1.Execute('อัปเดต tb1 set ffull=ffull + 1 จาก tb1 โดยที่ fid=120';
-
-
AdoConnection1.CommitTrans;
ยกเว้น
AdoConnection1.ย้อนกลับทรานส์;
จบ;
จบ;
================================================== ==============================================
การวิเคราะห์: ฉันไม่รู้ว่าคุณเคยเห็นปัญหาหรือไม่ ข้อมูลจะถูกตัดสินก่อน AdoConnection1.BeginTrans จากนั้น AdoConnection1.Execute จะถูกใช้เพื่อเปลี่ยนแปลงข้อมูล หากข้อมูลถูกแชร์ จากนั้นในช่วงเวลาหลังจากการตัดสินถึงก่อนหน้านี้ AdoConnection1.BeginTrans, tb1 ข้อมูลอาจมีการเปลี่ยนแปลง และการป้องกันธุรกรรมนี้ไม่มีประโยชน์
วิธีที่ถูกต้องคือการตัดสินใจและการแก้ไขต้องเป็นข้อมูลเดียวกัน ต่อไปนี้คือสองตัวอย่างของวิธีการ (ข้อแตกต่างคือสถานที่ที่เริ่มธุรกรรมแตกต่างกัน):
รหัส 1 (หลังจากใช้การป้องกันธุรกรรม ข้อมูลเดียวกันจะถูกตัดสินและแก้ไข):
================================================== ==============================================
var
adsTemp: TAdoDataSet;
isOk: บูลีน;
เริ่ม
AdoConnection1.BeginTrans;
พยายาม
adsTemp := TAdoDataSet.Create(ตนเอง);
พยายาม
adsTemp.Connection := AdoConnection1;
adsTemp.CommandText := 'เลือก fid, fnumber, ffull จาก tb1 โดยที่ fid=120';
adsTemp.เปิด;
ถ้า adsTemp.FieldByName('fnumber').AsInteger>100 แล้ว
เริ่ม
adsTemp.แก้ไข;
adsTemp.FieldByName('ffull').AsInteger := adsTemp.FieldByName('ffull').AsInteger + 1;
adsTemp.โพสต์;
จบ;
ในที่สุด
adsTemp.ฟรี;
จบ;
AdoConnection1.CommitTrans;
ยกเว้น
AdoConnection1.ย้อนกลับทรานส์;
จบ;
จบ;
================================================== ==============================================
รหัส 2 (โดยใช้การจับข้อยกเว้น หากการตัดสินและการแก้ไขไม่ใช่ข้อมูลเดียวกัน ข้อยกเว้นจะเกิดขึ้นระหว่าง adsTemp.Post นี่คือคุณลักษณะของวัตถุ ADODataSet):
================================================== ==============================================
var
adsTemp: TAdoDataSet;
isOk: บูลีน;
เริ่ม
adsTemp := TAdoDataSet.Create(ตนเอง);
พยายาม
adsTemp.Connection := AdoConnection1;
adsTemp.CommandText := 'เลือก fid, fnumber, ffull จาก tb1 โดยที่ fid=120';
adsTemp.เปิด;
ถ้า adsTemp.FieldByName('fnumber').AsInteger>100 แล้ว
เริ่ม
AdoConnection1.BeginTrans;
พยายาม
adsTemp.แก้ไข;
adsTemp.FieldByName('ffull').AsInteger := adsTemp.FieldByName('ffull').AsInteger + 1;
adsTemp.โพสต์;
AdoConnection1.CommitTrans;
ยกเว้น
AdoConnection1.ย้อนกลับทรานส์;
จบ;
จบ;
ในที่สุด
adsTemp.ฟรี;
จบ;
จบ;