मेरे पास कोड का एक टुकड़ा है जो INSERT विफल होने पर लेनदेन को वापस करने के लिए TRY / CATCH का उपयोग करता है। हालांकि, कोड के बीच में मेरे पास कोड का एक टुकड़ा है जो प्रति लूप राउंड में एक ईमेल भेजता है।

मेरी समस्या यह है कि लूप ईमेल भेजता है और फिर एक सम्मिलित करता है। तो मान लें कि 9 प्रक्रियाओं/राउंड के बाद, 10वां राउंड INSERT में विफल हो जाता है; तो पूरा लेनदेन वापस ले लिया जाता है, लेकिन 9 ईमेल पहले ही भेजे जा चुके हैं। मैं इसे कैसे सुधार सकता हूं ताकि ईमेल पहले न भेजे जाएं? या लेन-देन विफल होने पर भेजे जाने वाले किसी भी ईमेल से कैसे बचें?

परीक्षण उद्देश्यों के लिए मेरे कोड का एक सरलीकृत संस्करण यहां दिया गया है।

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[something]
AS
BEGIN
    SET NOCOUNT, XACT_ABORT ON; 

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    BEGIN TRY
        DECLARE @something INT

        DECLARE ROW_RES CURSOR FOR
            SELECT something 
            FROM something

        OPEN ROW_RES

        FETCH NEXT FROM ROW_RES INTO @something

        WHILE (@@fetch_status = 0) 
        BEGIN
            IF (@something > 0)
            BEGIN
                EXEC msdb.dbo.sp_send_dbmail
                     @profile_name = 'myprofile',
                     @from_address = 'do_not_reply@me.com',
                     @recipients = 'me@me.com',
                     @copy_recipients = 'ccme@me.com',
                     @subject = @email_subject,
                     @body = @email_body,
                     @body_format = 'html'
            END

            FETCH NEXT FROM ROW_RES INTO @something
        END

        IF (@something = false )
        BEGIN
            UPDATE something 
            SET something = (@something) 
            WHERE something = @something
        END
        ELSE IF (@something = true)
        BEGIN
            INSERT INTO something (something) 
            VALUES (@something)
        END

        COMMIT TRAN
    END TRY
    BEGIN CATCH
        DECLARE @MESSAGE NVARCHAR(2000), @SEVERITY INT, @STATE INT
        --See if there is a hanging transaction
        IF @@TRANCOUNT > 0 ROLLBACK TRAN
        --Rethrow the error to the calling application      
        SET @MESSAGE = ERROR_MESSAGE() 
        SET @SEVERITY = ERROR_SEVERITY() 
        SET @STATE = ERROR_STATE()
        RAISERROR(@MESSAGE, @SEVERITY, @STATE)      
    END CATCH

    SET NOCOUNT OFF;
END
CLOSE ROW_RES
DEALLOCATE ROW_RES
4
speedygonzales77 24 जुलाई 2017, 21:43

2 जवाब

सबसे बढ़िया उत्तर

समस्या यह है कि लेन-देन शुरू करने के लिए आपके पास एक BEGIN TRAN नहीं है। तो आपके बयान सभी एक संयुक्त लेनदेन के बजाय व्यक्तिगत ऑटो प्रतिबद्ध लेनदेन में चल रहे हैं।

यदि आप BEGIN TRAN को try ब्लॉक की शुरुआत में जोड़ते हैं तो आपका मौजूदा कोड वांछित के रूप में काम करना चाहिए।

1
Martin Smith 24 जुलाई 2017, 22:32

कर्सर के अंदर sp_send_dbmail को कॉल करने के बजाय, आप इसके बजाय एक कतार तालिका में आवश्यक सभी मेटा डेटा सम्मिलित कर सकते हैं, और कर्सर पूरा होने के बाद, यदि कोई समस्या नहीं थी, तो आप एक और कर्सर या लूप चला सकते हैं जो बस भेजता है कतार तालिका में प्रत्येक पंक्ति के लिए ईमेल।

3
Tab Alleman 24 जुलाई 2017, 21:56