ประโยชน์ของการใช้“ SET XACT_ABORT ON” ในขั้นตอนการจัดเก็บคืออะไร?


177

ประโยชน์ของการใช้SET XACT_ABORT ONในขั้นตอนการจัดเก็บคืออะไร?


2
การอ้างอิงmsdn
Tim Abell

3
นี่เป็นบทความที่ดีมากเกี่ยวกับมัน: sommarskog.se/error_handling/Part1.html
วิศวกรที่กลับรายการ

คำตอบ:


231

SET XACT_ABORT ONสั่งให้เซิร์ฟเวอร์ SQL ย้อนกลับธุรกรรมทั้งหมดและยกเลิกชุดงานเมื่อเกิดข้อผิดพลาดขณะทำงาน ครอบคลุมถึงคุณในกรณีที่คำสั่งหมดเวลาใช้งานที่เกิดขึ้นกับแอปพลิเคชันไคลเอนต์มากกว่าภายใน SQL Server เอง (ซึ่งไม่ได้ครอบคลุมโดยการXACT_ABORT OFFตั้งค่าเริ่มต้น)

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

มีภาพรวมที่ดีจริงๆเป็นบล็อกแดน Guzman ของ ,


41
เหตุใดจึงไม่เปิดใช้งานตามค่าเริ่มต้น
Mike W

1
เป็น XACT_ABORT ยังคงจำเป็นต้องใช้ถ้าคุณมีBEGIN TRY- BEGIN CATCHและROLLBACKกับBEGIN CATCHบล็อกใน SQL?
user20358

1
@ user20358 BEGIN TRY- BEGIN CATCHจะไม่จับสิ่งต่าง ๆ เช่นการหมดเวลาที่เกิดขึ้นกับแอปพลิเคชันไคลเอนต์และข้อผิดพลาด SQL บางอย่างนั้นไม่สามารถตรวจจับได้เช่นกันทำให้คุณมีธุรกรรมเปิดที่คุณไม่คาดหวัง
Tom Lint

37

ในความเห็นของฉัน 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


9
ยกเว้นการหมดเวลาของไคลเอ็นต์ ... และมุมมองของฉัน SET XACT_ABORT นั้นมีประสิทธิภาพมากขึ้นใน SQL 2005 เพราะพฤติกรรมสามารถคาดเดาได้มากขึ้น: แบทช์ที่น้อยกว่าการยกเลิกข้อผิดพลาด
gbn

7
ฉันเห็นด้วยบ้าง แต่ฉันวางแผนจัดการข้อผิดพลาดรอบเหตุการณ์ทั้งหมดเพราะฉันรู้ว่าฉันจะได้รับโทษในฐานะนักพัฒนา DBA หากการหมดเวลาของคำสั่งเกิดขึ้น
gbn

4
@RemusRusanu คุณจะจัดการกับการดำเนินงานฐานข้อมูลแบบซิงโครนัสที่ใช้เวลานานอีกต่อไปอย่างไร
Ian Boyd

5
เอกสารประกอบของ MSDN ระบุว่า: "XACT_ABORT จะต้องตั้งค่าสำหรับคำสั่งการปรับเปลี่ยนข้อมูลในการทำธุรกรรมโดยนัยหรือชัดเจนกับผู้ให้บริการ OLE DB ส่วนใหญ่รวมถึง SQL Server กรณีเดียวที่ตัวเลือกนี้ไม่จำเป็นต้องใช้คือถ้าผู้ให้บริการรองรับธุรกรรมซ้อน msdn.microsoft.com/en-us/library/ms188792(v=sql.120).aspx
Nathan

4
"ในความเห็นของฉัน SET XACT_ABORT ON ล้าสมัยจากการเพิ่ม BEGIN TRY / BEGIN CATCH" - ฉันได้ยินคุณ แต่โปรดดูsommarskog.se/error_handling/Part1.html
วิศวกรที่กลับรายการ

22

การอ้างอิง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 ทุกครั้งที่ไม่มีเหตุผลสำหรับการจัดการข้อผิดพลาดขั้นสูง


8

เกี่ยวกับการหมดเวลาไคลเอนต์และการใช้ XACT_ABORT เพื่อจัดการกับพวกเขาในความคิดของฉันมีอย่างน้อยหนึ่งเหตุผลที่ดีมากที่จะมี timeouts ในไคลเอนต์ APIs เช่น SqlClient และเพื่อป้องกันรหัสแอปพลิเคชันไคลเอนต์จากการหยุดชะงัก ในกรณีนี้รหัสลูกค้าไม่มีความผิด แต่ต้องป้องกันตนเองจากการบล็อกตลอดไปรอให้คำสั่งดำเนินการให้เสร็จสิ้นบนเซิร์ฟเวอร์ ในทางกลับกันหากการหมดเวลาของไคลเอ็นต์ต้องมีเพื่อปกป้องรหัสลูกค้าดังนั้น XACT_ABORT ON จะต้องป้องกันรหัสเซิร์ฟเวอร์จากการยกเลิกไคลเอ็นต์ในกรณีที่รหัสเซิร์ฟเวอร์ใช้เวลาในการประมวลผลนานกว่าที่ลูกค้าเต็มใจรอ


1

มันถูกใช้ในการจัดการธุรกรรมเพื่อให้แน่ใจว่าข้อผิดพลาดใด ๆ ส่งผลให้ธุรกรรมถูกย้อนกลับ

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