जब XACT_ABORT को चालू किया जाता है, तो किन मामलों में CATCH ब्लॉक के अंदर से लेनदेन किया जा सकता है?


13

मैं MSDN के बारे में TRY...CATCHऔर पढ़ रहा हूँ XACT_STATE

निम्नलिखित उदाहरण है कि एक निर्माण XACT_STATEके CATCHब्लॉक में उपयोग करता है यह TRY…CATCHनिर्धारित करने के लिए कि क्या लेनदेन करना है या वापस रोल करना है:

USE AdventureWorks2012;
GO

-- SET XACT_ABORT ON will render the transaction uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;
        -- A FOREIGN KEY constraint exists on this table. This 
        -- statement will generate a constraint violation error.
        DELETE FROM Production.Product
            WHERE ProductID = 980;

    -- If the delete operation succeeds, commit the transaction. The CATCH
    -- block will not execute.
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    -- Test XACT_STATE for 0, 1, or -1.
    -- If 1, the transaction is committable.
    -- If -1, the transaction is uncommittable and should 
    --     be rolled back.
    -- XACT_STATE = 0 means there is no transaction and
    --     a commit or rollback operation would generate an error.

    -- Test whether the transaction is uncommittable.
    IF (XACT_STATE()) = -1
    BEGIN
        PRINT 'The transaction is in an uncommittable state.' +
              ' Rolling back transaction.'
        ROLLBACK TRANSACTION;
    END;

    -- Test whether the transaction is active and valid.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT 'The transaction is committable.' + 
              ' Committing transaction.'
        COMMIT TRANSACTION;   
    END;
END CATCH;
GO

जो मुझे समझ में नहीं आ रहा है, मुझे उसकी देखभाल और जांच क्यों करनी चाहिए XACT_STATE?

कृपया ध्यान दें, कि ध्वज उदाहरण में XACT_ABORTसेट है ON

यदि TRYब्लॉक के अंदर कोई गंभीर त्रुटि है , तो नियंत्रण पास हो जाएगा CATCH। इसलिए, अगर मैं अंदर हूं, तो मुझे CATCHपता है कि लेन-देन में एक समस्या है और वास्तव में इस मामले में एकमात्र समझदार बात यह है कि इसे वापस करना है, है न?

लेकिन, MSDN का यह उदाहरण बताता है कि ऐसे मामले हो सकते हैं जब नियंत्रण में पारित किया जाता है CATCHऔर फिर भी यह लेनदेन करने के लिए समझ में आता है। किसी को कुछ व्यावहारिक उदाहरण प्रदान कर सकता है जब यह हो सकता है, जब यह समझ में आता है?

मैं क्या मामलों नियंत्रण के अंदर पारित किया जा सकता में नहीं दिख रहा है CATCHएक सौदे कि प्रतिबद्ध किया जा सकता है के साथ जब XACT_ABORTके लिए निर्धारित हैON

MSDN लेख के बारे SET XACT_ABORTमें एक उदाहरण है जब एक लेन-देन के अंदर कुछ कथन सफलतापूर्वक निष्पादित होते हैं और जब XACT_ABORTसेट किया जाता है तो कुछ विफल हो जाते हैं OFF, मैं समझता हूं कि। लेकिन, SET XACT_ABORT ONऐसा कैसे हो सकता है जो ब्लॉक के XACT_STATE()अंदर 1 रिटर्न देता है CATCH?

प्रारंभ में, मैंने इस कोड को इस तरह लिखा होगा:

USE AdventureWorks2012;
GO

-- SET XACT_ABORT ON will render the transaction uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;
        -- A FOREIGN KEY constraint exists on this table. This 
        -- statement will generate a constraint violation error.
        DELETE FROM Production.Product
            WHERE ProductID = 980;

    -- If the delete operation succeeds, commit the transaction. The CATCH
    -- block will not execute.
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    -- Some severe problem with the transaction
    PRINT 'Rolling back transaction.';
    ROLLBACK TRANSACTION;
END CATCH;
GO

मैक्स वर्नन द्वारा एक उत्तर को ध्यान में रखते हुए, मैं इस तरह कोड लिखूंगा। उन्होंने दिखाया कि यह जांचने के लिए समझ में आता है कि क्या प्रयास करने से पहले एक सक्रिय लेनदेन है ROLLBACK। फिर भी, के साथ ब्लॉक या तो सभी पर लेन-देन या कोई लेन-देन बर्बाद हो सकता है। तो, किसी भी मामले में कुछ भी नहीं है । क्या मै गलत हु?SET XACT_ABORT ONCATCHCOMMIT

USE AdventureWorks2012;
GO

-- SET XACT_ABORT ON will render the transaction uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;
        -- A FOREIGN KEY constraint exists on this table. This 
        -- statement will generate a constraint violation error.
        DELETE FROM Production.Product
            WHERE ProductID = 980;

    -- If the delete operation succeeds, commit the transaction. The CATCH
    -- block will not execute.
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    -- Some severe problem with the transaction
    IF (XACT_STATE()) <> 0
    BEGIN
        -- There is still an active transaction that should be rolled back
        PRINT 'Rolling back transaction.';
        ROLLBACK TRANSACTION;
    END;

END CATCH;
GO

जवाबों:


8

यह पता चला है कि यदि सेट किया गया है तो ब्लॉक के अंदर से लेनदेन नहीं किया जा सकता है ।CATCHXACT_ABORTON

MSDN से उदाहरण कुछ भ्रामक है, क्योंकि चेक का अर्थ है कि XACT_STATEकुछ मामलों में 1 वापस आ सकता है और यह COMMITलेनदेन के लिए संभव हो सकता है ।

IF (XACT_STATE()) = 1
BEGIN
    PRINT 'The transaction is committable.' + 
          ' Committing transaction.'
    COMMIT TRANSACTION;   
END;

यह सच नहीं है, यदि सेट किया गया है तो ब्लॉक के XACT_STATEअंदर 1 कभी नहीं लौटेगा ।CATCHXACT_ABORTON

ऐसा लगता है कि MSDN नमूना कोड मुख्य रूप XACT_STATE()से XACT_ABORTसेटिंग की परवाह किए बिना फ़ंक्शन के उपयोग को स्पष्ट करने के लिए था । सैंपल कोड XACT_ABORTसेट ONऔर टू दोनों के साथ काम करने के लिए पर्याप्त सामान्य लगता है OFF। यह सिर्फ इतना है कि XACT_ABORT = ONचेक IF (XACT_STATE()) = 1अनावश्यक हो जाता है।


Erland Sommarskog द्वारा SQL Server में Error और Transaction हैंडलिंग के बारे में लेखों का एक बहुत अच्छा विस्तृत सेट है । में भाग 2 - त्रुटियाँ का वर्गीकरण वह एक व्यापक तालिका प्रस्तुत करता है कि कहते हैं एक साथ त्रुटियों के सभी वर्गों और कैसे वे एसक्यूएल सर्वर द्वारा नियंत्रित किया जाता है और कैसे कर रहे हैं TRY ... CATCHऔर XACT_ABORTव्यवहार में बदलाव लाती।

+-----------------------------+---------------------------++------------------------------+
|                             |     Without TRY-CATCH     ||        With TRY-CATCH        |
+-----------------------------+-------+-------+-----+-----++------------------+-----+-----+
|              SET XACT_ABORT |  OFF  |  ON   | OFF | ON  ||    ON or OFF     | OFF | ON  |
+-----------------------------+-------+-------+-----+-----++------------------+-----+-----+
| Class Name                  |    Aborts     |   Rolls   ||    Catchable     |   Dooms   |
|                             |               |   Back    ||                  |transaction|
+-----------------------------+-------+-------+-----+-----++------------------+-----+-----+
| Fatal errors                |  Connection   |    Yes    ||       No         |    n/a    |
| Batch-aborting              |     Batch     |    Yes    ||       Yes        |    Yes    |
| Batch-only aborting         |     Batch     | No  | Yes ||       Yes        | No  | Yes |
| Statement-terminating       | Stmnt | Batch | No  | Yes ||       Yes        | No  | Yes |
| Terminates nothing at all   |    Nothing    |    No     ||       Yes        | No  | Yes |
| Compilation: syntax errors  |  (Statement)  |    No     ||       Yes        | No  | Yes |
| Compilation: binding errors | Scope | Batch | No  | Yes || Outer scope only | No  | Yes |
| Compilation: optimisation   |     Batch     |    Yes    || Outer scope only |    Yes    |
| Attention signal            |     Batch     | No  | Yes ||       No         |    n/a    |
| Informational/warning msgs  |    Nothing    |    No     ||       No         |    n/a    |
| Uncatchable errors          |    Varying    |  Varying  ||       No         |    n/a    |
+-----------------------------+-------+-------+-----+-----++------------------+-----+-----+

तालिका का अंतिम कॉलम प्रश्न का उत्तर देता है। लेन-देन के साथ TRY-CATCHऔर XACT_ABORT ONसभी संभावित मामलों में बर्बाद होता है।

प्रश्न के दायरे से बाहर एक नोट। जैसा कि एरलैंड कहते हैं, यह स्थिरता निम्नलिखित कारणों में से एक XACT_ABORTहै ON:

मैंने पहले ही सिफारिश दी है कि आपके संग्रहीत प्रक्रियाओं में कमांड शामिल होना चाहिए SET XACT_ABORT, NOCOUNT ON। यदि आप ऊपर दी गई तालिका को देखते हैं, तो आप देखते हैं कि XACT_ABORTप्रभाव में, कुछ उच्च स्तर की संगति है। उदाहरण के लिए, लेन-देन हमेशा बर्बाद होता है। निम्नलिखित में, मैं कई उदाहरण दिखाऊंगा, जहां मैं सेट XACT_ABORTकरता हूं OFF, ताकि आप समझ सकें कि आपको इस डिफ़ॉल्ट सेटिंग से क्यों बचना चाहिए।


7

मैं इससे अलग तरीके से संपर्क करूंगा। XACT_ABORT_ONएक स्लेज हैमर है, आप एक अधिक परिष्कृत दृष्टिकोण का उपयोग कर सकते हैं, अपवाद हैंडलिंग और नेस्टेड लेनदेन देखें :

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end
go

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


मैं आपके जवाब की सराहना करते हैं, लेकिन सवाल है कि क्या हम वास्तव में स्थापित करना चाहिए नहीं है XACT_ABORTकरने के लिए ONया OFF
व्लादिमीर बारानोव

7

TL, DR / कार्यकारी सारांश: प्रश्न के इस भाग के बारे में:

मैं क्या मामलों नियंत्रण के अंदर पारित किया जा सकता में नहीं दिख रहा है CATCHएक सौदे कि प्रतिबद्ध किया जा सकता है के साथ जब XACT_ABORTके लिए निर्धारित हैON

मैं काफी अब इस पर परीक्षण का एक सा किया है और मैं किसी भी मामले हैं, जहां नहीं मिल सकता है XACT_STATE()रिटर्न 1एक के अंदर CATCHब्लॉक जब @@TRANCOUNT > 0 और के सत्र संपत्ति XACT_ABORTहै ON। और वास्तव में, सेट XACT_ABORT के लिए वर्तमान MSDN पृष्ठ के अनुसार :

जब SET XACT_ABORT चालू होता है, यदि कोई Transact-SQL स्टेटमेंट रन-टाइम त्रुटि उठाता है, तो पूरा लेनदेन समाप्त हो जाता है और वापस चला जाता है।

यह कथन आपकी अटकलों और मेरे निष्कर्षों के साथ सहमति से प्रतीत होता है।

MSDN लेख के बारे SET XACT_ABORTमें एक उदाहरण है जब लेनदेन के अंदर कुछ स्टेटमेंट सफलतापूर्वक निष्पादित होते हैं और कुछ XACT_ABORTसेट होने पर विफल हो जाते हैंOFF

सच है, लेकिन उस उदाहरण में बयान एक ब्लॉक के भीतर नहीं हैं TRYTRYब्लॉक के भीतर वही कथन अभी भी त्रुटि के कारण होने वाले किसी भी बयान के लिए निष्पादन को रोकेंगे, लेकिन यह मानते हुए कि जब ब्लॉक को नियंत्रण पारित किया जाता XACT_ABORTहै OFF, तो CATCHलेन-देन अभी भी भौतिक रूप से मान्य है, जिसमें सभी पूर्व परिवर्तन त्रुटि के बिना हुआ था। और कर सकते हैं , प्रतिबद्ध रहें कि यदि इच्छा है, या वे लुढ़का वापसी हो सकती है। दूसरी ओर, यदि XACT_ABORTहै ONतो किसी भी पूर्व परिवर्तन स्वचालित रूप से लुढ़का वापस कर रहे हैं, और उसके बाद या तो आप के लिए विकल्प दिए गए हैं: क) इस मुद्दे को एकROLLBACKजो कि लेन-देन के पहले से ही केवल एक स्थिति की स्वीकृति है क्योंकि लेन-देन पहले से ही शून्य पर रीसेट किया @@TRANCOUNTगया था 0, या b) एक त्रुटि मिली। बहुत पसंद नहीं है, है ना?

इस पहेली के लिए संभवतः एक महत्वपूर्ण विवरण जो उस प्रलेखन में स्पष्ट नहीं SET XACT_ABORTहै, वह यह है कि इस सत्र की संपत्ति, और उदाहरण के लिए कोड भी SQL सर्वर 2000 (प्रलेखन संस्करणों के बीच लगभग समान है) के बाद से हो गया है, जो TRY...CATCHनिर्माण से पहले था एसक्यूएल सर्वर 2005 में शुरू की है कि प्रलेखन को देखते हुए फिर से और (उदाहरण को देखकर बिनाTRY...CATCH ) का उपयोग कर XACT_ABORT ONका कारण बनता है एक तत्काल लेन-देन का रोल-बैक: वहाँ "uncommittable" (कृपया ध्यान दें की कोई लेन-देन राज्य में कोई जिक्र नहीं है कि वहाँ है सभी "अप्रतिस्पर्धी" उस SET XACT_ABORTदस्तावेज़ में लेन-देन की स्थिति )।

मुझे लगता है कि यह निष्कर्ष निकालना उचित है:

  1. TRY...CATCHSQL Server 2005 में निर्माण की शुरूआत ने एक नए लेन-देन की स्थिति (यानी "uncommittable") और XACT_STATE()उस जानकारी को प्राप्त करने के लिए फ़ंक्शन की आवश्यकता पैदा की ।
  2. यदि वास्तव में निम्न में से दोनों सत्य हैं, तो ब्लॉक XACT_STATE()में जाँच करना CATCHही मायने रखता है:
    1. XACT_ABORTहै OFF(और XACT_STATE()हमेशा लौटना चाहिए -1और @@TRANCOUNTआपकी ज़रूरत होगी)
    2. आपके पास CATCHब्लॉक में तर्क है , या कहीं न कहीं श्रृंखला है, यदि कॉल नेस्टेड हैं, जो एक करने के बजाय एक परिवर्तन ( COMMITया यहां तक ​​कि किसी भी डीएमएल, डीडीएल, आदि बयान) करता है । (यह एक बहुत ही atypical उपयोग का मामला है) ** कृपया नीचे देखें नोट पर, UPDATE 3 अनुभाग में, Microsoft द्वारा अनौपचारिक अनुशंसा के संबंध में हमेशा इसके बजाय जाँच करने के लिए , और परीक्षण से पता चलता है कि उनका तर्क पैन नहीं करता है।ROLLBACKXACT_STATE()@@TRANCOUNT
  3. TRY...CATCHSQL सर्वर 2005 में निर्माण की शुरूआत , अधिकांश भाग के लिए, XACT_ABORT ONसत्र संपत्ति को मानती है क्योंकि यह लेन-देन पर अधिक से अधिक नियंत्रण प्रदान करती है (आपके पास कम से कम विकल्प है COMMIT, बशर्ते कि XACT_STATE()वापस न आए -1)।
    इसे देखने का एक और तरीका है, SQL सर्वर 2005 से पहले , XACT_ABORT ONएक त्रुटि होने पर प्रसंस्करण को रोकने के लिए एक आसान और विश्वसनीय तरीका प्रदान किया गया, जैसा कि @@ERRORप्रत्येक कथन के बाद जाँचने के लिए है ।
  4. इसके लिए प्रलेखन उदाहरण कोड XACT_STATE()गलत है, या सबसे भ्रामक है, जिसमें यह पता चलता है कि XACT_STATE() = 1कब XACT_ABORTहै ON

लंबा हिस्सा ;-)

हां, MSDN पर वह उदाहरण कोड थोड़ा भ्रामक है (यह भी देखें: @@ TRANCOUNT (रोलबैक) बनाम XACT_STATE ) ;-) और, मैं यह क्योंकि यह या तो पता चलता है कुछ है कि कोई मतलब नहीं (कारण यह है कि आप पूछ रहे हैं के बारे में के लिए: यदि आप भी एक "committable" लेन-देन हो सकता है बनाता है भ्रामक है महसूस CATCHब्लॉक जब XACT_ABORTहै ON), या यहाँ तक कि यह संभव है, तो यह अभी भी एक तकनीकी संभावना पर ध्यान केंद्रित करता है जो कुछ लोग कभी भी चाहते हैं या आवश्यकता होगी, और इस कारण की अनदेखी करते हैं कि इसकी आवश्यकता होने की अधिक संभावना है।

यदि TRY ब्लॉक के अंदर एक गंभीर पर्याप्त त्रुटि है, तो नियंत्रण CATCH में पारित हो जाएगा। इसलिए, अगर मैं CATCH के अंदर हूं, तो मुझे पता है कि लेन-देन में एक समस्या है और वास्तव में इस मामले में एकमात्र समझदार बात यह है कि इसे वापस लेना है, है न?

मुझे लगता है कि अगर हमें यह सुनिश्चित करने में मदद मिलेगी कि हम एक ही पृष्ठ पर हैं तो कुछ शब्दों और अवधारणाओं से क्या मतलब है:

  • "गंभीर पर्याप्त त्रुटि": बस स्पष्ट होने के लिए, TRY ... CATCH अधिकांश त्रुटियों को फंसा देगा। जो नहीं पकड़ा जाएगा, उसकी सूची उस लिंक किए गए MSDN पृष्ठ पर "त्रुटी से अप्रभावित एक TRY ... CATCH निर्माण" खंड के अंतर्गत सूचीबद्ध है।

  • "अगर मैं CATCH के अंदर हूं, तो मुझे पता है कि लेन-देन में कोई समस्या है" (उन्हें चरण जोड़ा गया है): यदि "लेन-देन" से आपका मतलब है कि एक स्पष्ट लेनदेन में बयानों को समूह द्वारा आपके द्वारा निर्धारित कार्य की तार्किक इकाई है, तो सबसे अधिक संभावना हां। मुझे लगता है कि हम में से अधिकांश लोग डीबी के लोगों को इस बात से सहमत करते हैं कि रोलिंग-बैक "करने के लिए एकमात्र समझदारी वाली बात है" क्योंकि हम संभवतः एक समान दृष्टिकोण रखते हैं कि हम स्पष्ट लेनदेन का उपयोग कैसे और क्यों करते हैं और एक परमाणु इकाई बनाने के लिए क्या कदम उठाने चाहिए काम की।

    लेकिन, अगर आप काम की वास्तविक इकाइयों से मतलब रखते हैं जिन्हें स्पष्ट लेनदेन में वर्गीकृत किया जा रहा है, तो नहीं, आप नहीं जानते कि लेन-देन अपने आप में एक समस्या है। आप केवल यह जानते हैं कि स्पष्ट रूप से परिभाषित लेन-देन के भीतर निष्पादित करने वाले एक बयान में त्रुटि हुई है। लेकिन यह डीएमएल या डीडीएल बयान नहीं हो सकता है। और यहां तक ​​कि अगर यह एक डीएमएल बयान था, तो लेन-देन स्वयं अभी भी सराहनीय हो सकता है।

ऊपर दिए गए दो बिंदुओं को देखते हुए, हमें संभवतः लेनदेन के बीच एक अंतर निकालना चाहिए जिसे आप "कमिट" नहीं कर सकते हैं, और जिन्हें आप "नहीं" चाहते हैं।

जब कोई XACT_STATE()रिटर्न देता है 1, तो इसका मतलब है कि लेन-देन "सराहनीय" है, कि आपके पास एक विकल्प है COMMITया ROLLBACK। आप शायद इसे कमिट नहीं करना चाहते हैं , लेकिन अगर कुछ कठिन-से-आने-के-साथ-साथ-एक-उदाहरण-के लिए-आप कारण चाहते थे, तो कम से कम आप कर सकते थे क्योंकि लेन-देन के कुछ हिस्सों ने सफलतापूर्वक पूरा किया।

लेकिन जब कोई XACT_STATE()रिटर्न देता है -1, तो आपको वास्तव में इसकी आवश्यकता है ROLLBACKक्योंकि लेन-देन का कुछ हिस्सा खराब स्थिति में चला गया। अब, मैं इस बात से सहमत हूँ कि अगर नियंत्रण को केटच ब्लॉक में पारित कर दिया गया है, तो यह सिर्फ जांच करने के लिए पर्याप्त है @@TRANCOUNT, क्योंकि अगर आप लेन-देन कर सकते हैं, तो आप क्यों करना चाहते हैं?

लेकिन यदि आप उदाहरण के शीर्ष पर नोटिस करते हैं, तो XACT_ABORT ONचीजों को थोड़ा बदलने की सेटिंग । आप एक नियमित त्रुटि हो सकता है, ऐसा करने के बाद BEGIN TRANकि पकड़ने ब्लॉक करने के लिए नियंत्रण पारित करेंगे जब XACT_ABORTहै OFFऔर XACT_STATE () वापस आ जाएगी 1। लेकिन, अगर XACT_ABORT है ON, तो किसी भी 'ol' त्रुटि के लिए Transaction "निरस्त" (यानी अमान्य) है और फिर XACT_STATE()वापस आ जाएगा -1। इस मामले में, ब्लॉक के XACT_STATE()भीतर जांच करना बेकार लगता है CATCHक्योंकि यह हमेशा लगता है कि -1कब वापस लौटना XACT_ABORTहै ON

तो फिर किस XACT_STATE()लिए है? कुछ सुराग हैं:

  • TRY...CATCH"अपरिवर्तनीय लेनदेन और XACT_STATE" अनुभाग के तहत MSDN पृष्ठ के लिए , कहते हैं:

    एक त्रुटि जो TRY ब्लॉक के बाहर लेन-देन को समाप्त कर देती है, एक TRY ब्लॉक के अंदर त्रुटि होने पर लेन-देन के लिए एक अपरिहार्य स्थिति में प्रवेश करती है।

  • "रिमार्क्स" अनुभाग के तहत सेट XACT_ABORT के लिए MSDN पृष्ठ कहता है:

    जब सेट XACT_ABORT बंद होता है, तो कुछ मामलों में केवल त्रुटि उत्पन्न करने वाले Transact-SQL स्टेटमेंट को वापस ले लिया जाता है और लेन-देन संसाधित हो जाता है।

    तथा:

    XACT_ABORT को SQL सर्वर सहित अधिकांश OLE DB प्रदाताओं के विरुद्ध एक अंतर्निहित या स्पष्ट लेनदेन में डेटा संशोधन विवरणों के लिए चालू होना चाहिए।

  • "रिमार्क्स" अनुभाग के तहत BEGIN परिवहन के लिए MSDN पृष्ठ कहता है:

    BEGIN ट्रांजेक्शन स्टेटमेंट द्वारा शुरू किया गया लोकल ट्रांजेक्शन एक डिस्ट्रीब्यूटेड ट्रांजैक्शन के लिए बढ़ा दिया जाता है, यदि स्टेटमेंट करने या रोल बैक करने से पहले निम्नलिखित एक्शन किए जाते हैं:

    • एक INSERT, DELETE, या अद्यतन कथन जो किसी लिंक किए गए सर्वर पर दूरस्थ तालिका का संदर्भ देता है। INSERT, UPDATE, या DELETE स्टेटमेंट विफल हो जाता है यदि लिंक किए गए सर्वर तक पहुँचने के लिए उपयोग किए जाने वाले OLE DB प्रदाता ITransactionJoin इंटरफ़ेस का समर्थन नहीं करता है।

सबसे अधिक उपयोग लिंक्ड सर्वर डीएमएल स्टेटमेंट के संदर्भ में होता है। और मुझे विश्वास है कि मैं खुद सालों पहले इसमें भाग गया था। मुझे सभी विवरण याद नहीं हैं, लेकिन इसका दूरस्थ सर्वर के उपलब्ध न होने से कुछ लेना-देना था, और किसी कारण से, यह त्रुटि TRY ब्लॉक के भीतर नहीं पकड़ी गई और कभी CATCH को नहीं भेजी गई और इसलिए इसने ऐसा किया यह नहीं होना चाहिए जब एक टिप्पणी। बेशक, यह जांच में विफल होने या संभवतः दोनों के बजाय सेट नहीं होने का मुद्दा हो सकता है । और मुझे याद है कि आपने जो कुछ कहा है, अगर आप लिंक्ड सर्वर और / या वितरित लेनदेन का उपयोग करते हैं, तो आपको उपयोग करने और / या करने की आवश्यकता है , लेकिन मैं अब उस दस्तावेज़ को ढूंढ नहीं सकता। अगर मुझे यह नहीं मिला, तो मैं इसे लिंक के साथ अपडेट कर दूंगा।XACT_ABORTONXACT_STATE()XACT_ABORT ONXACT_STATE()

फिर भी, मैंने कई चीजों की कोशिश की है और एक परिदृश्य को खोजने में असमर्थ हूं जो रिपोर्टिंग के साथ ब्लॉक पर XACT_ABORT ONनियंत्रण रखता है और पास करता है ।CATCHXACT_STATE()1

के प्रभाव को देखने के लिए ये उदाहरण आज़माएं XACT_ABORTके मूल्य पर XACT_STATE():

SET XACT_ABORT OFF;

BEGIN TRY
    BEGIN TRAN;

    SELECT 1/0 AS [DivideByZero]; -- error, yo!

    COMMIT TRAN;
END TRY
BEGIN CATCH
    SELECT @@TRANCOUNT AS [@@TRANCOUNT],
            XACT_STATE() AS [XactState],
            ERROR_MESSAGE() AS [ErrorMessage]

    IF (@@TRANCOUNT > 0)
    BEGIN
        ROLLBACK;
    END;
END CATCH;

GO ------------------------------------------------

SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRAN;

    SELECT 1/0 AS [DivideByZero]; -- error, yo!

    COMMIT TRAN;
END TRY
BEGIN CATCH
    SELECT @@TRANCOUNT AS [@@TRANCOUNT],
            XACT_STATE() AS [XactState],
            ERROR_MESSAGE() AS [ErrorMessage]

    IF (@@TRANCOUNT > 0)
    BEGIN
        ROLLBACK;
    END;
END CATCH;

GO ------------------------------------------------

SET XACT_ABORT ON;

BEGIN TRY
    SELECT 1/0 AS [DivideByZero]; -- error, yo!
END TRY
BEGIN CATCH
    SELECT @@TRANCOUNT AS [@@TRANCOUNT],
            XACT_STATE() AS [XactState],
            ERROR_MESSAGE() AS [ErrorMessage]
END CATCH;

अपडेट करें

इस प्रश्न पर इन टिप्पणियों के आधार पर मूल प्रश्न का हिस्सा नहीं है:

मैं पर Erland के लेख के माध्यम से पढ़ने किया गया है त्रुटि और लेन-देन हैंडलिंग वह जहां का कहना है कि XACT_ABORTहै OFFविरासत कारणों के लिए डिफ़ॉल्ट रूप से और सामान्य रूप से हम करने के लिए यह निर्धारित करना चाहिए ON
...
"... यदि आप अनुशंसा का पालन करते हैं और SET XACT_ABORT ON के साथ चलते हैं, तो लेनदेन हमेशा ख़त्म हो जाएगा।"

XACT_ABORT ONहर जगह उपयोग करने से पहले , मैं सवाल करता हूं: वास्तव में यहां क्या प्राप्त किया जा रहा है? मुझे ऐसा करने के लिए आवश्यक नहीं पाया गया है और आम तौर पर वकील करते हैं कि आपको इसका उपयोग केवल आवश्यक होने पर ही करना चाहिए। आप या नहीं चाहते हैं ROLLBACK@ रेमस के उत्तर में दिखाए गए टेम्पलेट का उपयोग करके आसानी से संभाल सकते हैं , या जो मैं वर्षों से उपयोग कर रहा हूं वह अनिवार्य रूप से एक ही चीज है लेकिन बिना सेव पॉइंट के, जैसा कि इस उत्तर में दिखाया गया है (जो कि नेस्टेड कॉल संभालती है):

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


अद्यतन २

मैंने थोड़ा और परीक्षण किया, इस बार एक छोटा .NET कंसोल ऐप बनाकर, ऐप लेयर में एक ट्रांज़ैक्शन बनाकर, किसी भी SqlCommandऑब्जेक्ट (यानी के माध्यम से using (SqlTransaction _Tran = _Connection.BeginTransaction()) { ...) को निष्पादित करने से पहले , साथ ही एक बयान के बजाय बैच-एबॉर्टिंग त्रुटि का उपयोग करके। -बेटिंग त्रुटि, और पाया कि:

  1. एक "असुविधाजनक" लेनदेन वह है जो अधिकांश भाग के लिए पहले से ही लुढ़का हुआ है (परिवर्तन पूर्ववत किया गया है), लेकिन @@TRANCOUNTअभी भी> 0 है।
  2. जब आपके पास "असम्मानजनक" लेन-देन होता है, तो आप इसे जारी नहीं कर सकते हैं COMMITजो उत्पन्न करेगा और यह कहते हुए त्रुटि करेगा कि लेन-देन "अप्रचलित" है। आप इसे अनदेखा भी नहीं कर सकते / कुछ भी नहीं हो सकता है जब बैच समाप्त होता है, तो यह कहते हुए एक त्रुटि उत्पन्न होगी कि बैच एक लेन-देन के साथ पूरा हो गया है, लेन-देन रहित है और इसे वापस रोल किया जाएगा (इसलिए, उम, अगर यह ऑटो-रोल-बैक वैसे भी होगा क्यों त्रुटि फेंक परेशान?)। तो आपको एक स्पष्ट जारी करना होगाROLLBACK , शायद तत्काल CATCHब्लॉक में नहीं , लेकिन बैच समाप्त होने से पहले।
  3. एक में TRY...CATCHनिर्माण, जब XACT_ABORTहै OFF, त्रुटियों कि लेन-देन को समाप्त होगा स्वचालित रूप से वे एक के बाहर हुआ था TRYइस तरह के बैच-निरस्त त्रुटियों के रूप में ब्लॉक के रूप में "uncommitable" यह छोड़ रहा है, काम पूर्ववत नहीं बल्कि Tranasction को समाप्त कर देगा। जारी ROLLBACKकरना लेनदेन को बंद करने के लिए आवश्यक औपचारिकता अधिक है, लेकिन काम पहले से ही लुढ़का हुआ है।
  4. जब XACT_ABORTहै ON, सबसे त्रुटियों बैच-निरस्त किया जा रहा के रूप में कार्य है, और सीधे ऊपर (# 3) बुलेट बिंदु में वर्णित के रूप इसलिए व्यवहार करते हैं।
  5. XACT_STATE()कम से कम एक CATCHब्लॉक में, -1बैच-गर्भपात त्रुटियों के लिए दिखाएगा यदि त्रुटि के समय एक सक्रिय लेनदेन था।
  6. XACT_STATE()कभी-कभी 1तब भी लौटता है जब कोई सक्रिय लेनदेन नहीं होता है। यदि @@SPID(अन्य लोगों के साथ) SELECTसूची में है XACT_STATE(), तो XACT_STATE()1 तब वापस आएगा जब कोई सक्रिय लेनदेन नहीं होगा। यह व्यवहार SQL Server 2012 में प्रारंभ हुआ, और 2014 पर मौजूद है, लेकिन मैंने 2016 पर परीक्षण नहीं किया है।

उपरोक्त बिंदुओं को ध्यान में रखकर:

  • यह देखते हुए अंक # 4 और # 5, सबसे (या सभी?) के बाद से त्रुटियों एक लेन-देन "uncommitable" प्रस्तुत करना होगा, यह पूरी तरह जांच करने के लिए व्यर्थ लगता है XACT_STATE()में CATCHब्लॉक जब XACT_ABORTहै ONलौटे हमेशा रहेंगे मूल्य के बाद से -1
  • जाँच हो रही है XACT_STATE()में CATCHब्लॉक जब XACT_ABORTहै OFFऔर अधिक समझ में आता है क्योंकि वापसी मान कम से कम कुछ बदलाव करना होगा क्योंकि यह वापस आ जाएगी 1बयान-निरस्त त्रुटियों के लिए। हालाँकि, यदि आप हममें से अधिकांश की तरह कोड करते हैं, तो यह अंतर अर्थहीन है क्योंकि आप किसी ROLLBACKभी तरह से इस तथ्य के लिए कॉल कर रहे होंगे कि कोई त्रुटि हुई है।
  • यदि आपको ऐसी स्थिति मिलती है जो ब्लॉक COMMITमें वारंट जारी करती CATCHहै, तो उसके मूल्य की जांच करें XACT_STATE(), और सुनिश्चित करें SET XACT_ABORT OFF;
  • XACT_ABORT ONलगता है TRY...CATCHनिर्माण पर कोई फायदा नहीं हुआ ।
  • मुझे कोई परिदृश्य नहीं मिल रहा है जहाँ जाँच XACT_STATE()करने से बस जाँच करने पर सार्थक लाभ मिलता है @@TRANCOUNT
  • मुझे यह भी पता नहीं है कि ब्लॉक में XACT_STATE()रिटर्न कहां है । मुझे लगता है कि यह एक प्रलेखन त्रुटि है।1CATCHXACT_ABORTON
  • हां, आप ऐसा लेन-देन वापस कर सकते हैं जिसे आपने स्पष्ट रूप से शुरू नहीं किया था। और उपयोग करने के संदर्भ में XACT_ABORT ON, यह एक म्यूट पॉइंट है क्योंकि TRYब्लॉक में होने वाली त्रुटि स्वचालित रूप से परिवर्तनों को रोल-बैक कर देगी।
  • TRY...CATCHनिर्माण से अधिक लाभ है XACT_ABORT ONस्वचालित रूप से नहीं पूरे लेन-देन को रद्द करने, और इसलिए लेन-देन (जब तक देने में XACT_STATE()रिटर्न 1) के लिए प्रतिबद्ध होना करने के लिए (भले ही यह किनारे से होता है)।

का उदाहरण XACT_STATE()लौटने -1जब XACT_ABORTहै OFF:

SET XACT_ABORT OFF;

BEGIN TRY
    BEGIN TRAN;

    SELECT CONVERT(INT, 'g') AS [ConversionError];

    COMMIT TRAN;
END TRY
BEGIN CATCH
    DECLARE @State INT;
    SET @State = XACT_STATE();
    SELECT @@TRANCOUNT AS [@@TRANCOUNT],
            @State AS [XactState],
            ERROR_MESSAGE() AS [ErrorMessage];

    IF (@@TRANCOUNT > 0)
    BEGIN
        SELECT 'Rollin back...' AS [Transaction];
        ROLLBACK;
    END;
END CATCH;

अद्यतन 3

UPDATE 2 अनुभाग में आइटम # 6 से संबंधित ( XACT_STATE()जब कोई सक्रिय लेन-देन नहीं होने पर संभावित गलत मान लौटाया जाता है):

  • SQL सर्वर 2012 (अब तक 2012 SP2 और 2014 SP1 के खिलाफ परीक्षण किया गया) में अजीब / गलत व्यवहार शुरू हुआ
  • SQL सर्वर संस्करण 2005, 2008 और 2008 R2 में, XACT_STATE()ट्रिगर या INSERT...EXECपरिदृश्य में उपयोग किए जाने पर अपेक्षित मानों की रिपोर्ट नहीं की जाती है: xact_state () का उपयोग यह निर्धारित करने के लिए मज़बूती से नहीं किया जा सकता है कि क्या लेन-देन घटा है । हालाँकि, इन 3 संस्करणों में (मैंने केवल 2008 R2 पर परीक्षण किया है), गलत तरीके से रिपोर्ट नहींXACT_STATE() करता है जब एक साथ उपयोग किया जाता है ।1SELECT@@SPID
  • यहां उल्लिखित व्यवहार के खिलाफ एक कनेक्ट बग दर्ज किया गया है, लेकिन "बाय डिजाइन" के रूप में बंद है: XACT_STATE () SQL 2012 में एक गलत लेनदेन स्थिति वापस कर सकता है । हालांकि, परीक्षण एक DMV से चयन करते समय किया गया था और यह निष्कर्ष निकाला गया था कि ऐसा करने से स्वाभाविक रूप से एक सिस्टम उत्पन्न लेनदेन होगा, कम से कम कुछ DMV के लिए। यह एमएस द्वारा अंतिम प्रतिक्रिया में भी कहा गया था कि:

    ध्यान दें कि एक IF स्टेटमेंट, और FROM के बिना एक सेलेक्ट भी, एक ट्रांजैक्शन शुरू न करें।
    उदाहरण के लिए, SELECT XACT_STATE () चल रहा है यदि आपके पास पहले से मौजूद लेन-देन नहीं है तो 0 वापस आ जाएगा।

    उन बयानों को गलत उदाहरण दिया गया है:

    SELECT @@TRANCOUNT AS [TRANCOUNT], XACT_STATE() AS [XACT_STATE], @@SPID AS [SPID];
    GO
    DECLARE @SPID INT;
    SET @SPID = @@SPID;
    SELECT @@TRANCOUNT AS [TRANCOUNT], XACT_STATE() AS [XACT_STATE], @SPID AS [SPID];
    GO
  • इसलिए, नए कनेक्ट बग:
    XACT_STATE () 1 का उपयोग करता है जब कुछ सिस्टम चर के साथ चयन में उपयोग किया जाता है, लेकिन बिना क्लाज के

कृपया ध्यान दें कि "XACT_STATE () SQL 2012 में एक गलत लेनदेन स्थिति लौटा सकता है" कनेक्ट आइटम सीधे ऊपर, Microsoft (अच्छी तरह से, प्रतिनिधि) राज्यों से जुड़ा हुआ है:

@@ ट्रैन्काउंट BEGIN TRAN स्टेटमेंट की संख्या लौटाता है। इस प्रकार यह एक विश्वसनीय संकेतक नहीं है कि क्या कोई सक्रिय लेनदेन है। XACT_STATE () भी 1 लौटाता है यदि एक सक्रिय ऑटोकॉमिट लेनदेन है, और इस प्रकार एक अधिक विश्वसनीय संकेतक है कि क्या कोई सक्रिय लेनदेन है।

हालाँकि, मुझे विश्वास नहीं करने का कोई कारण नहीं मिल सकता है @@TRANCOUNT। निम्नलिखित परीक्षण से पता चलता है कि @@TRANCOUNTवास्तव 1में ऑटो-कमिट लेनदेन में वापस आता है :

--- begin setup
GO
CREATE PROCEDURE #TransactionInfo AS
SET NOCOUNT ON;
SELECT @@TRANCOUNT AS [TranCount],
       XACT_STATE() AS [XactState];
GO
--- end setup

DECLARE @Test TABLE (TranCount INT, XactState INT);

SELECT * FROM @Test; -- no rows

EXEC #TransactionInfo; -- 0 for both fields

INSERT INTO @Test (TranCount, XactState)
    EXEC #TransactionInfo;

SELECT * FROM @Test; -- 1 row; 1 for both fields

मैंने एक ट्रिगर के साथ एक असली टेबल पर भी परीक्षण किया और ट्रिगर के @@TRANCOUNTभीतर सटीक रिपोर्ट किया, 1भले ही कोई स्पष्ट लेनदेन शुरू नहीं हुआ था।


4

रक्षात्मक प्रोग्रामिंग के लिए आपको कोड लिखने की आवश्यकता होती है जो यथासंभव ज्ञात राज्यों को संभालता है, जिससे बग की संभावना कम हो जाती है।

एक रोलबैक निष्पादित किया जा सकता है या नहीं यह निर्धारित करने के लिए XACT_STATE () की जाँच करना बस एक अच्छा अभ्यास है। नेत्रहीन रूप से रोलबैक का प्रयास करने का मतलब है कि आप अनजाने में अपने TRY ... CATCH के अंदर त्रुटि का कारण बन सकते हैं।

एक रोलबैक एक TRY के अंदर विफल हो सकता है ... CATCH होगा यदि आपने स्पष्ट रूप से लेनदेन शुरू नहीं किया है। कोड ब्लॉक को कॉपी और पेस्ट करना आसानी से इसका कारण हो सकता है।


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

फिर भी, मैं इसकी सराहना करूंगा, यदि आप दूसरे भाग के संबंध में अपना उत्तर दे IF (XACT_STATE()) = 1 COMMIT TRANSACTION; सकते हैं - हम CATCHसराहनीय लेनदेन के साथ ब्लॉक के अंदर कैसे समाप्त हो सकते हैं ? मैं अंदर से कुछ (संभव) कचरा उठाने की हिम्मत नहीं करूंगा CATCH। मेरा तर्क यह है: अगर हम अंदर हैं तो CATCHकुछ गलत हो गया है, मैं डेटाबेस की स्थिति पर भरोसा नहीं कर सकता, इसलिए मुझे ROLLBACKजो भी मिला है , मैं उसे बेहतर करूंगा ।
व्लादिमीर बारानोव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.