SQL सर्वर - लेन-देन त्रुटि पर वापस?


193

हमारे पास क्लाइंट ऐप है जो SQL Server 2005 पर कुछ SQL चला रहा है जैसे कि निम्नलिखित:

BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;

यह एक लंबी स्ट्रिंग कमांड द्वारा भेजा जाता है।

यदि आवेषण में से एक विफल हो जाता है, या कमांड का कोई भी भाग विफल हो जाता है, तो क्या SQL Server लेनदेन को वापस करता है? यदि यह रोलबैक नहीं होता है, तो क्या मुझे इसे वापस रोल करने के लिए दूसरी कमांड भेजनी होगी?

मैं जिस एपीआई और भाषा का उपयोग कर रहा हूं, उसके बारे में कुछ बता सकता हूं, लेकिन मुझे लगता है कि SQL सर्वर को किसी भी भाषा के लिए समान प्रतिक्रिया देनी चाहिए।


जवाबों:


204

आप set xact_abort onत्रुटि के मामले में सुनिश्चित करें कि SQL रोल स्वचालित रूप से वापस करने के लिए अपने लेन-देन से पहले रख सकते हैं ।


1
क्या यह MS SQL 2K और उच्चतर पर काम करेगा? यह सबसे सरल उपाय लगता है।
jonathanpeppers

1
यह डॉक्स में 2000, 2005 और 2008 के लिए दिखाई देता है इसलिए मैं हां मानता हूं। हम इसे 2008 में उपयोग कर रहे हैं।

8
क्या मुझे इसे बंद करने की आवश्यकता है या यह प्रति सत्र है?
मार्क

5
@Marc का दायरा xact_abortकनेक्शन स्तर पर है।
कीथ

2
@AlexMcMillan DROP प्रक्रिया विवरण INSERT के विपरीत, डेटाबेस संरचना को संशोधित करता है, जो सिर्फ डेटा के साथ काम करता है। इसलिए इसे लेनदेन में नहीं लपेटा जा सकता। मैं देख रहा हूँ, लेकिन मूल रूप से यह कैसे है।
इस्कॉर्ट्सो

195

आप सही हैं कि पूरा लेनदेन वापस चालू हो जाएगा। आपको इसे वापस रोल करने के लिए आदेश जारी करना चाहिए।

आप इसे एक TRY CATCHब्लॉक में निम्नानुसार लपेट सकते हैं

BEGIN TRY
    BEGIN TRANSACTION

        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);

    COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN --RollBack in case of Error

    -- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH

2
मुझे DyingCactus का समाधान बेहतर लगता है, उसका कोड बदलने के लिए 1 पंक्ति है। अगर तुम्हारा अगर किसी कारण से बेहतर (या अधिक विश्वसनीय) मुझे बताएं।
जोनाथनपेपर्स

13
कोशिश कैच आपको त्रुटि को पकड़ने (और संभवतः ठीक करने) की क्षमता देता है और यदि आवश्यक हो तो एक कस्टम त्रुटि संदेश बढ़ाता है।
राज मोर

10
"कैप्चर और लॉग" "कैप्चर और फिक्स" की तुलना में अधिक बार, मुझे लगता है।
क्विलब्रेकर

24
कम से कम SQL Server 2008R2 और बाद में RAISERROR का सिंटैक्स गलत है। सही सिंटैक्स के लिए msdn.microsoft.com/en-us/library/ms178592.aspx देखें ।
एरिक जे।

2
@BornToCode यह सुनिश्चित करने के लिए कि लेन-देन मौजूद है .. कहते हैं कि आपने अपना लेन-देन दिए गए शर्त ( try) में वापस कर दिया है , लेकिन बाद में कोड विफल हो जाता है। अधिक लेन-देन नहीं हैं, लेकिन आप अभी भी इसमें जा रहे हैं catch
गैब्रियल जीएम

42

यहाँ MSSQL सर्वर 2016 के साथ त्रुटि संदेश प्राप्त करने वाला कोड है:

BEGIN TRY
    BEGIN TRANSACTION 
        -- Do your stuff that might fail here
    COMMIT
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN

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

    -- Use RAISERROR inside the CATCH block to return error  
    -- information about the original error that caused  
    -- execution to jump to the CATCH block.  
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH

1
मुझे DECLARE @Var TYPE; SET @Var = ERROR;sql सर्वर 2005 में त्रुटियों को बढ़ाने के लिए उपयोग करना था । अन्यथा त्रुटियों को बढ़ाने के लिए उपरोक्त कोड पुराने DB के लिए भी काम करता है। एक स्थानीय चर के लिए एक डिफ़ॉल्ट मान असाइन करने की कोशिश कर रहा था जो समस्या पैदा कर रहा था।
jtlindsey

आप एक साधारण THROW का उपयोग कर सकते हैं; RAISERROR और ERROR_ * घोषणाओं के बजाय।
रॉडज़्मकी

21

MDSN लेख से, लेन-देन पर नियंत्रण (डेटाबेस इंजन)

यदि रन-टाइम स्टेटमेंट एरर (जैसे कि बाधा का उल्लंघन) बैच में होता है, तो डेटाबेस इंजन में डिफ़ॉल्ट व्यवहार केवल उस स्टेटमेंट को रोल करने के लिए होता है जिसने एरर उत्पन्न किया था। आप सेट XACT_ABORT कथन का उपयोग करके इस व्यवहार को बदल सकते हैं। SET XACT_ABORT ON को निष्पादित किए जाने के बाद, कोई भी रन-टाइम स्टेटमेंट त्रुटि वर्तमान लेनदेन का स्वत: रोलबैक करता है। संकलित त्रुटियां, जैसे संकलित त्रुटियां, SET XACT_ABORT से प्रभावित नहीं होती हैं। अधिक जानकारी के लिए, SET XACT_ABORT (Transact-SQL) देखें।

आपके मामले में, जब कोई आवेषण विफल हो जाता है तो यह पूर्ण लेनदेन को रोलबैक करेगा।


3
हमें सिंटैक्स त्रुटियों को संभालने की क्या आवश्यकता है? या गलतियों को संकलित करें? अगर उनमें से कोई भी होता है तो पूरे लेन-देन को वापस ले लिया जाना चाहिए
मॉन्स्टरमोरपीजी

एसएसडीटी परियोजनाओं के लिए संकलन संकलन / वाक्यविन्यास त्रुटियां हैं। :-)
जो कोडर

10

यदि आवेषण में से एक विफल हो जाता है, या कमांड का कोई भी भाग विफल हो जाता है, तो क्या SQL सर्वर लेनदेन को वापस करता है?

नहीं, यह नहीं है।

यदि यह रोलबैक नहीं होता है, तो क्या मुझे इसे वापस रोल करने के लिए दूसरी कमांड भेजनी होगी?

बेशक, आप जारी करना चाहिए ROLLBACKबजाय COMMIT

आप तय करने के लिए प्रतिबद्ध है या लेनदेन रोलबैक के लिए कि क्या चाहते हैं, आप को दूर करना चाहिए COMMIT, बयान से बाहर वाक्य आवेषण के परिणामों की जांच और उसके बाद जारी या तो COMMITया ROLLBACKजांच के परिणामों के आधार पर।


इसलिए अगर मुझे कोई त्रुटि मिलती है, तो "प्राथमिक कुंजी संघर्ष" कहें मुझे रोलबैक पर दूसरी कॉल भेजने की आवश्यकता है? मुझे लगता है यह सार्थक बात है। यदि नेटवर्क से संबंधित कोई त्रुटि है जैसे कि बहुत लंबे समय तक चलने वाले SQL स्टेटमेंट के दौरान कनेक्शन विच्छेद हो जाता है तो क्या होता है?
jonathanpeppers

2
जब कोई कनेक्शन बाहर निकलता है, तो अंतर्निहित नेटवर्क प्रोटोकॉल (जैसे Named Pipesया TCP) कनेक्शन को तोड़ देता है। जब कोई कनेक्शन टूट SQL Serverजाता है , तो वर्तमान में चल रहे सभी आदेशों को रोक देता है और लेनदेन को रोलबैक करता है।
क्वासोनि

1
इसलिए DyingCactus का समाधान ऐसा लगता है कि यह मेरे मुद्दे को ठीक करता है, मदद के लिए धन्यवाद।
जोनाथनपेपर्स 16

यदि आपको किसी भी त्रुटि पर गर्भपात करने की आवश्यकता है , तो हाँ, यह सबसे अच्छा विकल्प है।
क्वासोनि
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.