2012-03-15 9 views
12

मेरे पास एक संग्रहित प्रक्रिया है जिसे सहेजने की स्थिति सेट करने की आवश्यकता है ताकि कुछ परिस्थितियों में, यह सबकुछ पूर्ववत कर सके और कॉलर को त्रुटि कोड वापस कर सके , या इसे स्वीकार/प्रतिबद्ध करें और कॉलर को सफलता वापस कर दें। लेकिन मुझे यह काम करने की ज़रूरत है कि क्या कॉलर पहले ही लेनदेन शुरू कर चुका है या नहीं। डॉक्टर इस विषय पर बेहद उलझन में है। यहां मुझे लगता है कि काम करेगा, लेकिन मैं सभी विधियों में से कुछ निश्चित नहीं हूं।ट्रांसफर बनाम BEGIN ट्रांसएक्शन (एसक्यूएल सर्वर) लेनदेन को अच्छी तरह से घोंसला कैसे करें

बात यह है - यह Stored Procedure (SP) दूसरों द्वारा बुलाया जाता है। इसलिए मुझे नहीं पता कि उन्होंने लेनदेन शुरू किया है या नहीं ... भले ही मुझे उपयोगकर्ताओं को मेरे एसपी का उपयोग करने के लिए लेनदेन शुरू करने की आवश्यकता हो, फिर भी मुझे Save Points के उचित उपयोग के बारे में प्रश्न हैं ...

मेरा यदि कोई लेनदेन प्रगति पर है, तो एसपी जांच करेगा, और यदि नहीं, तो BEGIN TRANSACTION के साथ एक शुरू करें। यदि कोई लेनदेन पहले ही प्रगति पर है, तो यह SAVE TRANSACTION MySavePointName के साथ एक सेव पॉइंट बना देगा, और इस तथ्य को बचाएगा कि मैंने यही किया है।

फिर अगर मुझे अपने परिवर्तन वापस लेना है, तो मैंने BEGIN TRANSACTION पहले किया था, तो मैं ROLLBACK TRANSACTION करूँगा। अगर मैंने सेव पॉइंट किया है, तो मैं ROLLBACK TRANSACTION MySavePointName करूँगा। यह परिदृश्य महान काम करता प्रतीत होता है।

यहां वह जगह है जहां मुझे थोड़ा उलझन मिलता है - अगर मैं अपना काम पूरा करना चाहता हूं, अगर मैंने लेनदेन शुरू किया है तो मैं COMMIT TRANSACTION निष्पादित करूंगा। लेकिन अगर मैंने एक सेव प्वाइंट बनाया है? मैं COMMIT TRANSACTION MySavePointName की कोशिश की है, लेकिन फिर फोन करने वाले अपने लेन-देन करने का प्रयास और एक त्रुटि हो जाता है:

The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.

तो मैं तो सोच रहा हूँ - एक बचाने के बिंदु वापस लुढ़का जा सकता है (कि काम करता है: ROLLBACK TRANSACTION MySavePointName वापस रोल नहीं होगा फोन करने वाले का लेन-देन)। लेकिन शायद किसी को इसे "प्रतिबद्ध" करने की आवश्यकता नहीं है? यह केवल वहां रहता है, यदि आपको इसे वापस रोल करने की आवश्यकता है, लेकिन मूल लेनदेन किए जाने के बाद (या वापस लुढ़काया गया) दूर हो जाता है?

यदि लेनदेन "घोंसला" करने का "बेहतर" तरीका है, तो कृपया कुछ प्रकाश भी डालें। मुझे पता नहीं चला है कि BEGIN TRANSACTION के साथ घोंसला कैसे करें, लेकिन केवल रोलबैक या मेरा आंतरिक लेनदेन करें। लगता है कि ROLLBACK हमेशा शीर्ष लेनदेन पर वापस आ जाएगा, जबकि COMMIT बस @@trancount में कमी करता है।

+0

आपका खोज एक जवाब के रूप में पोस्ट के लायक हो सकता है। –

+0

@Andriy ठीक है, मैंने यही किया - मेरे संपादन को हटा दिया और इसके बजाय इसे एक उत्तर के रूप में इस्तेमाल किया। धन्यवाद। –

उत्तर

19

मेरा मानना ​​है कि मैं इस समझ गए होंगे अब सब बाहर, इसलिए मैं अपने ही सवाल का जवाब होगा ...

मैं अपने निष्कर्ष ब्लॉग किया गया है अगर आप http://geekswithblogs.net/bbiales/archive/2012/03/15/how-to-nest-transactions-nicely---quotbegin-transactionquot-vs-quotsave.aspx

तो मेरी सपा में अधिक जानकारी के लिए चाहते हैं अगर वहाँ कोई है शुरू होता है कुछ इस तरह के साथ, एक नई लेन-देन शुरू करने के लिए, लेकिन एक सहेजें प्वाइंट का उपयोग करता है, तो एक से प्रगति में है:

DECLARE @startingTranCount int 
SET @startingTranCount = @@TRANCOUNT 

IF @startingTranCount > 0 
    SAVE TRANSACTION mySavePointName 
ELSE 
    BEGIN TRANSACTION 
-- … 

फिर, परिवर्तन के लिए प्रतिबद्ध करने के लिए तैयार करते हैं, आप केवल तब प्रतिबद्ध करने के लिए की जरूरत है हमने खुद लेनदेन शुरू किया:

IF @startingTranCount = 0 
    COMMIT TRANSACTION 

और अंत में, बस अपने परिवर्तनों को अब तक वापस रोल:

-- Roll back changes... 
IF @startingTranCount > 0 
    ROLLBACK TRANSACTION MySavePointName 
ELSE 
    ROLLBACK TRANSACTION 
+0

'लेनदेन बचाने' के बाद एक नया नेस्टेड लेनदेन शुरू करने का कोई कारण नहीं है? – sotn

+0

नीचे घोंसले लेनदेन के बारे में एक लेख का एक लिंक है। यदि एक नेस्टेड लेनदेन किया जाता है, तो यह घोंसले लेनदेन की गिनती को कम करता है लेकिन कुछ भी नहीं करता है। तो यदि बाहरी लेनदेन किया जाता है, तो सब कुछ है, अगर इसे वापस घुमाया जाता है, तो सबकुछ वापस "लुप्त हो जाता है, जिसमें आपके" प्रतिबद्ध "होते हैं। यदि नेस्टेड लेनदेन रोलबैक करता है, तो यह दोनों स्वयं और बाहरी लेनदेन को वापस ले जाता है। यदि आप केवल अपने लेन-देन को बिना किसी लेनदेन को प्रभावित किए बिना रोलबैक करना चाहते हैं, तो यहां वर्णित तकनीक का उपयोग करें। –

+0

यहां नेस्टेड लेनदेन के बारे में लेख है: https://technet.microsoft.com/en-us/library/ms189336%28v=sql.105%29.aspx?f=255&MSPPError=-2147217396 –

10

विस्तार Brian B's answer

यह सुनिश्चित करता है कि सहेजें बिंदु नाम अद्वितीय है और SQL Server 2012 की नई TRY/CATCH/THROW सुविधाओं का उपयोग करता है।

DECLARE @mark CHAR(32) = replace(newid(), '-', ''); 
DECLARE @trans INT = @@TRANCOUNT; 

IF @trans = 0 
    BEGIN TRANSACTION @mark; 
ELSE 
    SAVE TRANSACTION @mark; 

BEGIN TRY 
    -- do work here 

    IF @trans = 0 
     COMMIT TRANSACTION @mark; 
END TRY 
BEGIN CATCH 
    IF xact_state() = 1 OR (@trans = 0 AND xact_state() <> 0) ROLLBACK TRANSACTION @mark; 
    THROW; 
END CATCH 
+0

मैं वापस नहीं गया था थोड़ी देर में इस पोस्ट के लिए, लेकिन टेम्पलेट से प्यार है कि आप अगली क्वेरी में verbatim का पुन: उपयोग कर सकते हैं। अच्छा वृद्धि –

+0

मैंने कोशिश ब्लॉक के अंदर लेनदेन विवरण शुरू करने के लिए एमएसडीएन सुझावों पर देखा है। क्या इस पैटर्न में ऐसा कुछ कारण हो सकता है या यह पूरी तरह से सुरक्षित है? –

+0

मैं पकड़ ब्लॉक में अगर कथन के बारे में उलझन में हूं। लेनदेन को वापस क्यों घुमाएं यदि xact state = -1। यह <> - 1 नहीं होना चाहिए? –

2

मैं अपने संग्रहीत प्रक्रिया में लेन-देन प्रबंधक के इस प्रकार का इस्तेमाल किया है:

CREATE PROCEDURE Ardi_Sample_Test 
     @InputCandidateID INT 
    AS 
     DECLARE @TranCounter INT; 
     SET @TranCounter = @@TRANCOUNT; 
     IF @TranCounter > 0 
      SAVE TRANSACTION ProcedureSave; 
     ELSE 
      BEGIN TRANSACTION; 
     BEGIN TRY 

      /* 
      <Your Code> 
      */ 

      IF @TranCounter = 0 
       COMMIT TRANSACTION; 
     END TRY 
     BEGIN CATCH 
      IF @TranCounter = 0 
       ROLLBACK TRANSACTION; 
      ELSE 
       IF XACT_STATE() <> -1 
        ROLLBACK TRANSACTION ProcedureSave; 

      DECLARE @ErrorMessage NVARCHAR(4000); 
      DECLARE @ErrorSeverity INT; 
      DECLARE @ErrorState INT; 
      SELECT @ErrorMessage = ERROR_MESSAGE(); 
      SELECT @ErrorSeverity = ERROR_SEVERITY(); 
      SELECT @ErrorState = ERROR_STATE(); 

      RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState); 
     END CATCH 
    GO 
संबंधित मुद्दे