เป็นวิธีที่ดีที่สุดในการเพิ่มการจัดการข้อผิดพลาดใน SQL 2005 procs จัดเก็บคืออะไร?


11

เป็นวิธีที่ดีในการทำให้ procs ที่เก็บไว้มีประสิทธิภาพเพียงพอที่จะสามารถปรับขนาดได้ดีมากและยังมีการจัดการข้อผิดพลาดอะไร

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


2
ลองใช้บล็อก TRY CATCH ที่ใหม่กว่าใน SQL Server 2005 sommarskog.se/error_handling_2005.html
Sankar Reddy

สวัสดี @Kalalapy ~ ฉันอยากจะแนะนำในอนาคตที่จะถามคำถามแต่ละข้อด้วยตนเองและวิธีการที่เราสามารถมีคำตอบเฉพาะที่มุ่งเน้นไปที่คำถามเดียวในแต่ละครั้ง ฉันขอแนะนำให้คุณทำเช่นนั้นกับคำถามนี้
jcolebrand

คำตอบ:


12

Alex Kuznetsov มีบทที่ยอดเยี่ยมในหนังสือของเขาDefensive Database Programming (บทที่ 8) ที่ครอบคลุม T-SQL TRY ... จับ, ธุรกรรม T-SQL & การตั้งค่า XACT_ABORT และการใช้การจัดการข้อผิดพลาดฝั่งไคลเอ็นต์ มันจะช่วยคุณได้มากในการตัดสินใจว่าตัวเลือกใดที่เหมาะสมที่สุดสำหรับสิ่งที่คุณต้องทำให้สำเร็จ

มีให้บริการฟรีที่ไซต์นี้ ฉันไม่มีส่วนเกี่ยวข้องใด ๆ กับ บริษัท แต่ฉันเป็นเจ้าของเวอร์ชันสำเนายากของหนังสือเล่มนั้น

มีรายละเอียดเล็ก ๆ น้อย ๆ มากมายในเรื่องนี้ซึ่งอธิบายโดย Alex ได้เป็นอย่างดี

ตามคำขอของ Nick ... (แต่ไม่ใช่ทั้งหมดนี้อยู่ในบท)

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

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

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

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


คำแนะนำที่ดีและหนังสือที่ดีมาก!
แมเรียน

เรดเกตให้บริการหนังสืออิเล็กทรอนิกส์ฟรีที่มีประโยชน์มากมายและอันนี้เป็นหนังสือที่ดีที่สุดเล่มหนึ่ง ข้อเสนอแนะที่ดี
Matt M

ไม่ใช่หนังสือของพวกเขาทุกคนที่ทำเช่นนี้ แต่หนังสือ "Defensive ... " ของ Kuznetsov รุ่นฟรีไม่มี 2 บทที่ผ่านมาในระดับธุรกรรมการแยกและการพัฒนาการเปลี่ยนแปลงที่อยู่รอดพร้อมกัน สำหรับฉัน. เนื้อหาในนั้นมีมูลค่าการซื้อ
Phil Helmer

7

นี่คือแม่แบบของเรา (ลบบันทึกข้อผิดพลาด)

หมายเหตุ:

  • หากไม่มี XACT_ABORT จะต้องจับคู่ TXN ทั้งหมดเริ่มต้นและคอมมิชชัน / ย้อนกลับ
  • การลดความมุ่งมั่น @@ TRANCOUNT
  • การย้อนกลับส่งกลับ @@ TRANCOUNT ให้เป็นศูนย์ดังนั้นคุณจะได้รับข้อผิดพลาด 266
  • คุณไม่สามารถย้อนกลับเลเยอร์ปัจจุบันเท่านั้น (เช่น decrement @@ TRANCOUNT เมื่อย้อนกลับ)
  • XACT_ABORT ระงับข้อผิดพลาด 266
  • proc ที่จัดเก็บแต่ละรายการจะต้องสอดคล้องกับแม่แบบเดียวกันดังนั้นการโทรแต่ละครั้งจึงเป็นแบบอะตอมมิก
  • การตรวจสอบย้อนกลับนั้นซ้ำซ้อนจริง ๆ เนื่องจาก XACT_ABORT อย่างไรก็ตามมันทำให้ฉันรู้สึกดีขึ้นดูแปลก ๆ โดยไม่ต้องและอนุญาตให้สถานการณ์ที่คุณไม่ต้องการมัน
  • สิ่งนี้ช่วยให้ TXN ฝั่งไคลเอ็นต์ (เช่น LINQ)
  • Remus Rusanuมีกระสุนที่คล้ายกันที่ใช้บันทึกคะแนน ฉันชอบโทร DB อะตอมมิกและไม่ใช้การปรับปรุงบางส่วนเช่นบทความของพวกเขา

... ดังนั้นอย่าสร้าง TXN มากกว่าที่คุณต้องการ

อย่างไรก็ตาม

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

จะเป็นอย่างไรถ้า @@ TRANCOUNT มากกว่า 0 คุณไม่ทำงานหรือมีข้อเสนอแนะ?
kacalapy

@kacalapy: ไม่มีสิ่งใดเป็นธุรกรรมที่ซ้อนกันดังนั้นเราจึงไม่เริ่มscribd.com/doc/49579859/33/Nested-Transactions-Are-Real
gbn

3

ฉันใช้ลอง / จับ แต่ฉันยังรวบรวมข้อมูลให้มากที่สุดและเขียนลงใน errorlog หลังจากย้อนกลับ ในตัวอย่างนี้ "LogEvent" เป็นกระบวนงานที่เก็บไว้ซึ่งเขียนไปยังตาราง EventLog ซึ่งมีรายละเอียดของสิ่งที่เกิดขึ้น GetErrorInfo () เป็นการเรียกใช้ฟังก์ชันที่ส่งคืนข้อความแสดงข้อผิดพลาดที่แน่นอน

เมื่อเกิดข้อผิดพลาดข้อมูลจะถูกรวบรวมขั้นตอนจะข้ามไปยังส่วนการจัดการข้อผิดพลาดและออกย้อนกลับ ข้อมูลถูกเขียนลงในบันทึกจากนั้นขั้นตอนจะออก

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

exec LogEvent @Process, @Database, 'พยายามแทรก blah blah blah'
ลองเริ่มต้น
  แทรกลงใน MyTable
  เลือกค่า
    จาก MyOtherTable

  เลือก @rowcount = @@ ROWCOUNT
ลองใช้
- ข้อผิดพลาดการจัดการ
เริ่มต้นจับ
  เลือก @error = ERROR_NUMBER ()
         @rowcount = -1,
         @TableAction = 'แทรก'
         @TableName = @Database + '.MyTable'
         @AdditionalInfo = '(พยายามแทรก blah blah blah)' + dbo.GetErrorInfo ()
   GOTO TableAccessError
สิ้นสุดการจับ

.
.
.
.

TableAccessError:
IF (@@ TRANCOUNT> 0) ย้อนกลับ
เลือก @output = upper (@TableAction) + 
       'ข้อผิดพลาด - เกิดข้อผิดพลาดขณะที่' + 
       กรณี (@TableAction)
         เมื่อ 'อัปเดต' จากนั้น 'อัปเดต'
         เมื่อ 'ลบ' แล้ว 'ลบ'
         อื่น @TableAction + 'ไอเอ็นจี'
       สิ้นสุด + 
       'บันทึก' + 
       กรณี (@TableAction) 
         เมื่อ 'เลือก' จากนั้น 'จาก' 
         เมื่อ 'อัปเดต' จากนั้น 'ใน' 
         เมื่อ 'แทรก' จากนั้น 'เป็น'
         อื่น 'จาก'   
         สิ้นสุด + 
         'the' + @TableName + 'ตาราง'
เลือก @output = @output + '@@ ข้อผิดพลาด:' + แปลง (varchar (8), @ ข้อผิดพลาด) 
เลือก @output = @output + '@@ ROWCOUNT:' + แปลง (varchar (8), @ rowcount) 

เลือก @output = @output + isnull (@AdditionalInfo, '')
exec LogEvent @Process, @Database, @Output
RAISERROR (@ เอาต์พุต, 16,1) พร้อมบันทึก
เลือก @ReturnCode = -1
GOTO THE_EXIT


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