एक संग्रहीत प्रक्रिया में लेनदेन


12

मुझे एक ट्रांजैक्शन में एक UPDATE और INSERT करने की आवश्यकता है। यह कोड अपने आप ठीक काम करता है, लेकिन मैं इसे आसानी से कॉल करने और आवश्यक मापदंडों में पारित करने में सक्षम होना चाहता हूं। जब मैं इस लेनदेन को एक संग्रहीत प्रक्रिया में घोंसला बनाने की कोशिश करता हूं तो मैं बहुत सारे वाक्यविन्यास त्रुटियों में भाग लेता हूं।

मैं निम्नलिखित कोड को कैसे अलग कर सकता हूं ताकि इसे आसानी से कहा जा सके?

BEGIN TRANSACTION AssignUserToTicket
GO

DECLARE @updateAuthor varchar(100)
DECLARE @assignedUser varchar(100)
DECLARE @ticketID bigint

SET @updateAuthor = 'user1'
SET @assignedUser = 'user2'
SET @ticketID = 123456

    UPDATE tblTicket SET ticketAssignedUserSamAccountName = @assignedUser WHERE (ticketID = @ticketID);
    INSERT INTO [dbo].[tblTicketUpdate]
           ([ticketID]
           ,[updateDetail]
           ,[updateDateTime]
           ,[userSamAccountName]
           ,[activity])
     VALUES
           (@ticketID,
           'Assigned ticket to ' + @assignedUser,
           GetDate(),
           @updateAuthor,
           'Assign');
GO
COMMIT TRANSACTION AssignUserToTicket

1
यदि आप अपने प्रश्नों में विवरण जोड़ते हैं तो यह निश्चित रूप से मदद करेगा कि वास्तव में "त्रुटियां" क्या हैं ( अपने प्रश्न के नीचे संपादित लिंक का उपयोग करें )। इसके अलावा, कृपया यात्रा करें । धन्यवाद!
मैक्स वर्नोन

जवाबों:


15

आपको उस कोड को CREATE PROCEDURE ...सिंटैक्स में लपेटने की आवश्यकता है , और GOउसके बाद BEGIN TRANSACTIONऔर पहले के बयानों को हटा दें COMMIT TRANSACTION

GO
CREATE PROCEDURE dbo.AssignUserToTicket
(
     @updateAuthor varchar(100)
    , @assignedUser varchar(100)
    , @ticketID bigint
)
AS
BEGIN
    BEGIN TRANSACTION;
    SAVE TRANSACTION MySavePoint;
    SET @updateAuthor = 'user1';
    SET @assignedUser = 'user2';
    SET @ticketID = 123456;

    BEGIN TRY
        UPDATE dbo.tblTicket 
        SET ticketAssignedUserSamAccountName = @assignedUser 
        WHERE (ticketID = @ticketID);

        INSERT INTO [dbo].[tblTicketUpdate]
            (
            [ticketID]
            ,[updateDetail]
            ,[updateDateTime]
            ,[userSamAccountName]
            ,[activity]
            )
        VALUES (
            @ticketID
            , 'Assigned ticket to ' + @assignedUser
            , GetDate()
            , @updateAuthor
            , 'Assign'
            );
        COMMIT TRANSACTION 
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRANSACTION MySavePoint; -- rollback to MySavePoint
        END
    END CATCH
END;
GO

यह भी ध्यान दें, मैंने कुछ त्रुटि होने की स्थिति में स्टेटमेंट TRY...CATCHकरने की अनुमति देने के लिए एक स्टेटमेंट ब्लॉक जोड़ा ROLLBACK TRANSACTIONहै। आपको शायद उससे बेहतर त्रुटि से निपटने की आवश्यकता है, लेकिन अपनी आवश्यकताओं के ज्ञान के बिना, यह सबसे मुश्किल है।

कुछ अच्छा पढ़ना:

  1. हमेशा स्कीमा निर्दिष्ट करें

  2. संग्रहित प्रक्रिया सर्वश्रेष्ठ अभ्यास

  3. बचने की बुरी आदतें


1
आप अभी भी सहेजे गए लेन-देन करना चाहते हैं। यदि आप एक एसपी में लेन-देन करते हैं और एसपी दूसरे लेनदेन के सामान में लिपट जाता है तो असफल होने वाला है। sqlstudies.com/2014/01/06/…
केनेथ फिशर

मुझे उस ओर इशारा करने के लिए धन्यवाद। मुझे पता है कि SQL सर्वर में कोई नेस्टेड लेनदेन नहीं हैं, हालांकि मुझे SAVE TRANSकमांड के निहितार्थ के बारे में पता नहीं था ।
मैक्स वर्नोन

8

यदि आप सही ढंग से नेस्टेड संग्रहीत कार्यविधियों को संभालना चाहते हैं जो लेनदेन को संभाल सकते हैं (चाहे टी-एसक्यूएल या ऐप कोड से शुरू किया गया हो) तो आपको निम्नलिखित उत्तर में वर्णित टेम्पलेट का पालन करना चाहिए:

क्या हमें C # कोड में लेन-देन के साथ-साथ संग्रहीत कार्यविधि को भी संभालने की आवश्यकता है

आप यहां जो प्रयास कर रहे हैं, उससे आपको दो अंतर दिखाई देंगे:

  1. ब्लॉक के RAISERRORभीतर का उपयोग CATCH। यह कॉलिंग स्तर (चाहे डीबी या ऐप लेयर में) तक की त्रुटि को बुदबुदाती है, इसलिए इस तथ्य के बारे में निर्णय लिया जा सकता है कि त्रुटि हुई।

  2. नहीं SAVE TRANSACTION। मुझे इसका उपयोग करने का मामला कभी नहीं मिला। मुझे पता है कि कुछ लोग इसे पसंद करते हैं, लेकिन मैंने जो भी काम किया है, उसमें किसी भी जगह मैंने कभी भी किसी भी नेस्टेड स्तर के भीतर होने वाली त्रुटि की धारणा निहित है कि जो भी काम पहले से किया गया था वह अमान्य था। SAVE TRANSACTIONआप का उपयोग करके केवल राज्य में वापस लौट रहे हैं, इस पूर्व प्रक्रिया को बुलाया जा रहा है, मौजूदा प्रक्रिया को अन्यथा वैध माना जाएगा।

    यदि आप अधिक विवरण चाहते हैं SAVE TRANSACTION, तो कृपया इस उत्तर में दी गई जानकारी देखें:

    जब एक संग्रहीत कार्यविधि से 3 संग्रहीत कार्यविधियाँ प्रारंभ की जाती हैं तो रोलबैक कैसे करें

    SAVE TRANSACTIONइसके साथ एक और समस्या इसके व्यवहार की बारीकियों की है, जैसा कि SAVE TRANSACTION के लिए MSDN पेज में दिया गया है (जोर दिया गया है :)

    किसी लेनदेन में डुप्लीकेट सेवपॉइंट नामों की अनुमति है, लेकिन एक रोलबैक ट्रांजेक्शन स्टेटमेंट जो कि सेवपॉइंट नाम को निर्दिष्ट करता है, केवल उस नाम का उपयोग करके ट्रांजैक्शन को सबसे हाल ही में सेव ट्रांजेक्शन में वापस लाएगा।

    मतलब, आपको प्रत्येक संग्रहीत कार्यविधि में प्रत्येक सहेजें बिंदु को देने के लिए बहुत सावधान रहने की आवश्यकता है, जो सभी संग्रहीत कार्यविधियों में सभी सहेजें बिंदुओं के बीच अद्वितीय है। निम्नलिखित उदाहरण इस बिंदु को चित्रित करते हैं।

    यह पहला उदाहरण दिखाता है कि जब आप सहेजें बिंदु नाम का पुन: उपयोग करते हैं तो क्या होता है; केवल सबसे निचले स्तर का सेव प्वाइंट रोल-बैक है।

    IF (OBJECT_ID(N'tempdb..#SaveTranTestA') IS NOT NULL)
    BEGIN
        DROP TABLE #SaveTranTestA;
    END;
    CREATE TABLE #SaveTranTestA (SomeVal INT NOT NULL);
    
    BEGIN TRAN; -- start level 1
    SAVE TRANSACTION MySavePoint;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    
    INSERT INTO #SaveTranTestA (SomeVal) VALUES (100);
    
    BEGIN TRAN; -- start level 2
    SAVE TRANSACTION MySavePoint;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 2
    
    INSERT INTO #SaveTranTestA (SomeVal) VALUES (200);
    
    COMMIT; -- exit level 2
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestA;
    -- 100
    -- 200
    
    ROLLBACK TRANSACTION MySavePoint; -- error occurred; undo actions up to this point
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestA;
    -- 100
    
    COMMIT; -- exit level 1
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 0
    SELECT * FROM #SaveTranTestA;
    -- 100

    यह दूसरा उदाहरण दिखाता है कि जब आप अद्वितीय सहेजें बिंदु नाम का उपयोग करते हैं तो क्या होता है; वांछित स्तर का सेव प्वाइंट लुढ़का हुआ है।

    IF (OBJECT_ID(N'tempdb..#SaveTranTestB') IS NOT NULL)
    BEGIN
        DROP TABLE #SaveTranTestB;
    END;
    CREATE TABLE #SaveTranTestB (SomeVal INT NOT NULL);
    
    BEGIN TRAN; -- start level 1
    SAVE TRANSACTION MySavePointUno;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    
    INSERT INTO #SaveTranTestB (SomeVal) VALUES (100);
    
    BEGIN TRAN; -- start level 2
    SAVE TRANSACTION MySavePointDos;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 2
    
    INSERT INTO #SaveTranTestB (SomeVal) VALUES (200);
    
    COMMIT; -- exit level 2
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestB;
    -- 100
    -- 200
    
    ROLLBACK TRANSACTION MySavePointUno; --error occurred; undo actions up to this point
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestB;
    -- <no rows>
    
    COMMIT; -- exit level 1
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 0
    SELECT * FROM #SaveTranTestB;
    -- <no rows>

यही कारण है कि मैं अपने SAVE ट्रांज़ेक्शन सेवपॉइंट नाम को बनाने के लिए @@ NESTLEVEL का उपयोग करता हूं।
विंसेंट वैंकलबर्ग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.