2010-05-19 19 views
5

मैं एसक्यूएल सर्वर पर एक विशेषज्ञ नहीं हूं। क्या यह एसक्यूएल सर्वर में चयन, INSERT ... के बैच में त्रुटियों को संभालने के लिए एक वैध पैटर्न है? (मैं v.2008 का उपयोग)एसक्यूएल सर्वर त्रुटि हैंडलिंग पैटर्न

BEGIN TRANSACTION 
    BEGIN TRY 
     -- statement 1 
     -- statement 2 
     -- statement 3 
     COMMIT TRANSACTION 
    END TRY 

    BEGIN CATCH 
     ROLLBACK TRANSACTION 
    END CATCH 

धन्यवाद

उत्तर

6

मैं इस तरह कुछ उपयोग करता हूं:

CREATE PROCEDURE ErrorHandlingPattern 
( @intParam  int 
    ,@varcharParam varchar(10) 
    ,@dateParam  datetime 
) 
AS 

BEGIN TRY 
    SET NOCOUNT ON 
    DECLARE @Rows    int   --store @@ROWCOUNT in this 
      ,@ErrorMsg   varchar(500) --temp string to build the contents of messages passed into RAISERROR calls 
      ,@LogInfo   varchar(5000) --will hold any info necessary for error debugging, append to this throughout the procedure with important info 
      ,@TransactionCount int   

    SELECT @[email protected]@TRANCOUNT 
      ,@LogInfo='@intParam='  +ISNULL(''''+CONVERT(varchar(10), @intParam  )+'''','NULL') 
       +', @varcharParam=' +ISNULL(''''+      @varcharParam +'''','NULL') 
       +', @dateParam=' +ISNULL(''''+CONVERT(varchar(10), @dateParam,121 )+'''','NULL') 
       +'; @@TRANCOUNT=' +ISNULL(''''+CONVERT(varchar(10), @@TRANCOUNT )+'''','NULL') 

    --validate parameters 
    IF @intParam .... 
    BEGIN --logical error 
     SET @ErrorMsg='Error, invalid value for @intParam: '+ISNULL(''''+CONVERT(varchar(10),@intParam)+'''','NULL') 
     RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block 
    END 

    IF @TransactionCount=0 --if we are already in a transaction, no need to start another, nesting transactions +rollback=warnings about transaction count not being the same as when the procedure started. 
    BEGIN 
     BEGIN TRANSACTION 
    END 

    --do your work here.... 
    INSERT/UPDATE/DELETE... 
    SELECT @[email protected]@ROWCOUNT 

    IF @Rows!=ExpectedValue 
    BEGIN --logical error 
     SET @ErrorMsg='Error, INSERT/UPDATE/DELETE of tableXYZ resulted in '+ISNULL(''''+CONVERT(varchar(10),@Rows)+'''','NULL')+' rows affected' 
     RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block 
    END 

    --append improtant info to log string 
    SET @LogInfo=ISNULL(@LogInfo,'')+'; INSERT/UPDATE/DELETE of tableXYZ resulted in '+ISNULL(''''+CONVERT(varchar(10),@Rows)+'''','NULL')+' rows affected' 

    IF @TransactionCount=0 --only end the transaction if it started here 
    BEGIN 
     COMMIT --put in try block to be able to catch any problems committing 
    END 
END TRY 
BEGIN CATCH 

    IF XACT_STATE()!=0 --if there is any error end the transaction ASAP 
    BEGIN 
     ROLLBACK TRANSACTION 
    END 

    --will echo back the complete original error message 
    DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int 
    SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE() 
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine) 

    --because the transaction was ROLLBACKed this insert will be recorded in the database 
    INSERT INTO YourErrorLog (...) VALUES (...ISNULL(@ErrorMessage,'')+ISNULL(@LogInfo,'')) 

    RETURN 999 

END CATCH 

RETURN 0 
GO 

चूंकि आप केवल a batch of SELECT, INSERT का बैच कर रहे हैं, तो आप केवल CREATE प्रक्रिया और पैरामीटर घोषणाओं को हटा सकते हैं और पहली पंक्ति BEGIN TRY पर शुरू हो सकती है। इसके अलावा, क्योंकि आप कोई प्रक्रिया नहीं बना रहे हैं, GOTO TheEnd के साथ किसी भी रिटर्न स्टेटमेंट को प्रतिस्थापित करें और स्क्रिप्ट के नीचे TheEnd: लेबल जोड़ें।

+0

यह बहुत पूरा है, धन्यवाद। मैं वास्तव में एक प्रक्रिया बना रहा हूं: मैंने अपने प्रश्न को थोड़ा सा सरल बना दिया। मैंने आज @@ ROWCOUNT और @@ ट्रांज़ैंट से बहुत खुश हूं। मैं हमेशा लंबे संग्रहित प्रो से परहेज करता हूं, बजाय बिट्स और एक्सेस 1 से 1 तक पहुंच जाता हूं (जो मैं वास्तव में मास्टर करता हूं)। अब "प्रो" प्राप्त करने की तरह लग रहा है ;-) –

3

लगभग:

BEGIN TRANSACTION; 

BEGIN TRY 
    -- Generate a constraint violation error. 
    DELETE FROM Production.Product 
    WHERE ProductID = 980; 
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 
     ROLLBACK TRANSACTION; 
END CATCH; 

IF @@TRANCOUNT > 0 
    COMMIT TRANSACTION; 

यह ट्राई/कैच पर MSDN प्रलेखीकरण से लिया गया है, जहां अन्य उदाहरण पाया जा सकता है: http://msdn.microsoft.com/en-us/library/ms175976.aspx

+0

अच्छा और तेज़। धन्यवाद –

+1

मैं हमेशा TRY ब्लॉक के भीतर 'BEGIN ट्रांज़ेक्शन' और 'COMMIT' सहित सबकुछ रखूंगा। क्या आप लेनदेन बनाने या करने में कोई समस्या नहीं लेना चाहेंगे? –

संबंधित मुद्दे