การทำธุรกรรมและลองจับในงาน SQL Server


9

เรามีการดำเนินงาน DML ในแต่ละขั้นตอนของงาน SQL Server เพื่อให้แน่ใจว่าการปรับปรุง / แทรกจะถูกรีดกลับในกรณีอะไรผิดพลาดผมได้ห่อการปรับเปลี่ยนข้อมูลของแต่ละขั้นตอนในTRY CATCHและTRANSACTIONบล็อก:

BEGIN TRY
    BEGIN TRANSACTION

        [[INSERT/update statements]] ...

    IF @@TRANCOUNT > 0
    BEGIN
        COMMIT TRANSACTION
        PRINT 'Successful.'
    END

END TRY

BEGIN CATCH
    SELECT
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage

    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK TRANSACTION
        PRINT 'Unsuccessful.'
    END
END CATCH

มันแน่ใจหรือไม่ว่าการเปลี่ยนแปลงข้อมูลจะถูกย้อนกลับในกรณีที่เกิดข้อผิดพลาด? หรือข้อควรพิจารณาอื่น ๆ ที่ควรนำมาพิจารณา?

จะเป็นวิธีที่ดีกว่าในการทำเช่นนั้น (โดยใช้การกำหนดค่า ฯลฯ )?

ขอบคุณ.

คำตอบ:


7

ฉันอยากจะแนะนำรูปแบบเหมือนรูปแบบจากการจัดการข้อยกเว้นและธุรกรรมซ้อน :

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

รูปแบบนี้ตรวจสอบXACT_STATE()ใน catch block เพื่อป้องกันการทำธุรกรรมที่ไม่สามารถทำได้ :

ธุรกรรมที่ไม่สามารถยอมรับได้และ XACT_STATE
หากมีข้อผิดพลาดที่สร้างขึ้นในบล็อก TRY ทำให้สถานะของธุรกรรมปัจจุบันไม่ถูกต้องธุรกรรมจะถูกจัดประเภทเป็นธุรกรรมที่ไม่สามารถยอมรับได้ ข้อผิดพลาดที่มักจะจบการทำธุรกรรมนอกบล็อกลองทำธุรกรรมที่จะเข้าสู่สถานะที่ไม่สามารถยอมรับได้เมื่อเกิดข้อผิดพลาดภายในบล็อกลอง ธุรกรรมที่ไม่สามารถยอมรับได้สามารถดำเนินการอ่านหรือทำธุรกรรมย้อนกลับเท่านั้น ธุรกรรมไม่สามารถดำเนินการคำสั่ง Transact-SQL ใด ๆ ที่จะสร้างการดำเนินการเขียนหรือการทำธุรกรรม COMMIT ฟังก์ชัน XACT_STATE คืนค่า -1 ถ้าธุรกรรมถูกจัดประเภทเป็นธุรกรรมที่ไม่สามารถยอมรับได้ เมื่อแบตช์เสร็จสิ้น Database Engine จะย้อนกลับธุรกรรมที่ไม่สามารถใช้งานได้ หากไม่มีการส่งข้อความแสดงข้อผิดพลาดเมื่อธุรกรรมเข้าสู่สถานะที่ไม่สามารถยอมรับได้ เมื่อแบตช์เสร็จสิ้นข้อความผิดพลาดจะถูกส่งไปยังแอปพลิเคชันไคลเอนต์ สิ่งนี้บ่งชี้ว่าตรวจพบธุรกรรมที่ไม่สามารถยอมรับได้และย้อนกลับ

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


ขอบคุณสำหรับคำตอบที่เป็นประโยชน์และเว็บไซต์ที่ยอดเยี่ยมของคุณ! อย่างไรก็ตามฉันสงสัยว่าถ้าฉันยังสามารถใช้รูปแบบนี้กับคำสั่ง DML แบบง่าย ๆ (ไม่ใช่ proc ที่เก็บไว้)? นอกจากนี้เราต้องบันทึกรายการดังต่อไปนี้ด้วยหรือไม่? (ฉันไม่มีร้านค้า proc ที่จะใช้): บันทึกธุรกรรม usp_my_procedure_name;
Sky

2

สิ่งที่คุณดูดีสำหรับฉัน ฉันขอแนะนำให้ทำบางสิ่งบางอย่างกับข้อมูลของหลักสูตรหลังจากที่คุณย้อนกลับธุรกรรมเช่นเขียนออกมาในบันทึก


1
ขอบคุณสำหรับการตอบกลับของคุณคุณช่วยให้คำแนะนำฉันในการเขียนลงในบันทึกได้ไหม
Sky

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