ประโยชน์ของการใช้SET XACT_ABORT ON
ในขั้นตอนการจัดเก็บคืออะไร?
ประโยชน์ของการใช้SET XACT_ABORT ON
ในขั้นตอนการจัดเก็บคืออะไร?
คำตอบ:
SET XACT_ABORT ON
สั่งให้เซิร์ฟเวอร์ SQL ย้อนกลับธุรกรรมทั้งหมดและยกเลิกชุดงานเมื่อเกิดข้อผิดพลาดขณะทำงาน ครอบคลุมถึงคุณในกรณีที่คำสั่งหมดเวลาใช้งานที่เกิดขึ้นกับแอปพลิเคชันไคลเอนต์มากกว่าภายใน SQL Server เอง (ซึ่งไม่ได้ครอบคลุมโดยการXACT_ABORT OFF
ตั้งค่าเริ่มต้น)
เนื่องจากการหมดเวลาของแบบสอบถามจะทำให้ธุรกรรมเปิดค้างSET XACT_ABORT ON
อยู่จึงขอแนะนำในขั้นตอนการจัดเก็บทั้งหมดที่มีธุรกรรมที่ชัดเจน (เว้นแต่คุณจะมีเหตุผลเฉพาะที่ต้องทำอย่างอื่น) เนื่องจากผลที่ตามมาของแอปพลิเคชันที่ทำงานกับการเชื่อมต่อ
มีภาพรวมที่ดีจริงๆเป็นบล็อกแดน Guzman ของ ,
BEGIN TRY
- BEGIN CATCH
และROLLBACK
กับBEGIN CATCH
บล็อกใน SQL?
BEGIN TRY
- BEGIN CATCH
จะไม่จับสิ่งต่าง ๆ เช่นการหมดเวลาที่เกิดขึ้นกับแอปพลิเคชันไคลเอนต์และข้อผิดพลาด SQL บางอย่างนั้นไม่สามารถตรวจจับได้เช่นกันทำให้คุณมีธุรกรรมเปิดที่คุณไม่คาดหวัง
ในความเห็นของฉัน SET XACT_ABORT ON นั้นล้าสมัยจากการเพิ่ม BEGIN TRY / BEGIN CATCH ใน SQL 2k5 ก่อนบล็อกข้อยกเว้นใน Transact-SQL มันยากมากที่จะจัดการข้อผิดพลาดและขั้นตอนที่ไม่สมดุลนั้นเป็นเรื่องธรรมดาเกินไป (ขั้นตอนที่มี @@ TRANCOUNT ที่แตกต่างกันที่ทางออกเมื่อเทียบกับรายการ)
ด้วยการเพิ่มการจัดการข้อยกเว้น Transact SQL นั้นง่ายกว่ามากในการเขียนขั้นตอนที่ถูกต้องที่รับประกันว่าจะทำธุรกรรมได้อย่างสมดุล เช่นฉันใช้แม่แบบนี้สำหรับการจัดการข้อยกเว้นและการทำธุรกรรมซ้อน :
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
end catch
end
go
ช่วยให้ฉันสามารถเขียนขั้นตอนปรมาณูที่ย้อนกลับเฉพาะงานของตนเองในกรณีที่เกิดข้อผิดพลาดที่สามารถกู้คืนได้
ปัญหาหลักอย่างหนึ่งของกระบวนการ Transact-SQL คือความบริสุทธิ์ของข้อมูล : บางครั้งพารามิเตอร์ที่ได้รับหรือข้อมูลในตารางล้วนผิดปกติส่งผลให้เกิดข้อผิดพลาดที่ซ้ำกันของคีย์ข้อผิดพลาดอ้างอิงข้อ จำกัด ตรวจสอบข้อผิดพลาดที่มีข้อ จำกัด เป็นต้น ท้ายที่สุดนั่นคือบทบาทของข้อ จำกัด เหล่านี้หากข้อผิดพลาดความบริสุทธิ์ของข้อมูลเหล่านี้เป็นไปไม่ได้และถูกจับโดยตรรกะทางธุรกิจข้อ จำกัด ทั้งหมดจะล้าสมัย (เพิ่มการพูดเกินจริงอย่างมากสำหรับเอฟเฟกต์) หาก XACT_ABORT เปิดอยู่ดังนั้นข้อผิดพลาดเหล่านี้ส่งผลให้การทำธุรกรรมทั้งหมดหายไปซึ่งตรงข้ามกับความสามารถในการบล็อกโค้ดข้อยกเว้นที่จัดการข้อยกเว้นได้อย่างสง่างาม ตัวอย่างทั่วไปพยายามทำ INSERT และเปลี่ยนกลับเป็น UPDATE เนื่องจากการละเมิด PK
การอ้างอิงMSDN :
เมื่อ SET XACT_ABORT เปิดอยู่หากคำสั่ง Transact-SQL ทำให้เกิดข้อผิดพลาดรันไทม์ธุรกรรมทั้งหมดจะถูกยกเลิกและย้อนกลับ เมื่อ SET XACT_ABORT ปิดในบางกรณีเฉพาะคำสั่ง Transact-SQL ที่ยกข้อผิดพลาดจะถูกย้อนกลับและธุรกรรมดำเนินการต่อไป
ในทางปฏิบัตินี่หมายความว่าบางข้อความอาจล้มเหลวทำให้การทำธุรกรรม 'เสร็จสมบูรณ์บางส่วน' และอาจไม่มีสัญญาณของความล้มเหลวนี้สำหรับผู้โทร
ตัวอย่างง่ายๆ:
INSERT INTO t1 VALUES (1/0)
INSERT INTO t2 VALUES (1/1)
SELECT 'Everything is fine'
รหัสนี้จะเรียกใช้ 'สำเร็จ' โดยที่ XACT_ABORT OFF และจะยุติลงด้วยข้อผิดพลาดกับ XACT_ABORT ON ('INSERT INTO t2' จะไม่ถูกดำเนินการและแอปพลิเคชันไคลเอนต์จะยกข้อยกเว้น)
เป็นวิธีที่ยืดหยุ่นมากขึ้นคุณสามารถตรวจสอบ @@ ข้อผิดพลาดหลังจากแต่ละคำสั่ง (โรงเรียนเก่า) หรือใช้ลอง ... จับบล็อก (MSSQL2005 +) โดยส่วนตัวฉันชอบตั้ง XACT_ABORT ON ทุกครั้งที่ไม่มีเหตุผลสำหรับการจัดการข้อผิดพลาดขั้นสูง
เกี่ยวกับการหมดเวลาไคลเอนต์และการใช้ XACT_ABORT เพื่อจัดการกับพวกเขาในความคิดของฉันมีอย่างน้อยหนึ่งเหตุผลที่ดีมากที่จะมี timeouts ในไคลเอนต์ APIs เช่น SqlClient และเพื่อป้องกันรหัสแอปพลิเคชันไคลเอนต์จากการหยุดชะงัก ในกรณีนี้รหัสลูกค้าไม่มีความผิด แต่ต้องป้องกันตนเองจากการบล็อกตลอดไปรอให้คำสั่งดำเนินการให้เสร็จสิ้นบนเซิร์ฟเวอร์ ในทางกลับกันหากการหมดเวลาของไคลเอ็นต์ต้องมีเพื่อปกป้องรหัสลูกค้าดังนั้น XACT_ABORT ON จะต้องป้องกันรหัสเซิร์ฟเวอร์จากการยกเลิกไคลเอ็นต์ในกรณีที่รหัสเซิร์ฟเวอร์ใช้เวลาในการประมวลผลนานกว่าที่ลูกค้าเต็มใจรอ
มันถูกใช้ในการจัดการธุรกรรมเพื่อให้แน่ใจว่าข้อผิดพลาดใด ๆ ส่งผลให้ธุรกรรมถูกย้อนกลับ