2016-05-06 11 views
6

मैं एक सी # डेवलपर सीख रहा हूं और अधिक टीएसक्यूएल सीख रहा हूं। मैं इस तरह एक पटकथा लिखी:क्या किसी लेन-देन को पकड़ने की आवश्यकता होती है?

begin transaction 
--Insert into several tables 
end transaction 

लेकिन मुझे बताया गया था कि एक अच्छा विचार नहीं था और कुछ इस तरह उपयोग करने के लिए:

BEGIN TRANSACTION; 

BEGIN TRY 
    -- Generate a constraint violation error. 
    DELETE FROM Production.Product 
    WHERE ProductID = 980; 
END TRY 
BEGIN CATCH 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber 
     ,ERROR_SEVERITY() AS ErrorSeverity 
     ,ERROR_STATE() AS ErrorState 
     ,ERROR_PROCEDURE() AS ErrorProcedure 
     ,ERROR_LINE() AS ErrorLine 
     ,ERROR_MESSAGE() AS ErrorMessage; 

    IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION; 
END CATCH; 

IF @@TRANCOUNT > 0 
    COMMIT TRANSACTION; 
GO 

मैं नहीं दिख रहा है यही कारण है कि दूसरे उदाहरण अधिक सही है । क्या पहला व्यक्ति वही काम नहीं करेगा? ऐसा लगता है कि पहला या तो सभी टेबल अपडेट करेगा, या बिल्कुल नहीं? मुझे नहीं लगता कि प्रतिबद्धता से पहले @@TRANCOUNT क्यों जांचना आवश्यक है।

+1

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

+2

यदि दूसरे उदाहरण में कुछ भी है, तो प्रयास प्रयास ब्लॉक में होना चाहिए, पकड़ने के बाद नहीं ... मुझे लगता है कि – Kritner

उत्तर

4

एक बार जब आप कोशिश ब्लॉक के अंदर हैं और वास्तविक कथन से पहले एक लेनदेन खोलें, और इसे सीधे प्रतिबद्ध करें, तो अपने लेनदेन को करने के लिए बैच के अंत में जाने के लिए अपने नियंत्रण की प्रतीक्षा न करें।

एक बार जब आप कोशिश ब्लॉक में हैं और आपने लेनदेन खोला है, अगर कुछ गलत हो जाता है तो नियंत्रण कैच ब्लॉक पर कूद जाएगा, बस अपने लेनदेन को रोलबैक करें और आवश्यकतानुसार अन्य त्रुटि प्रबंधन करें।

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

BEGIN TRY 

    BEGIN TRANSACTION 
    -- Multiple Inserts 
    INSERT INTO.... 
    INSERT INTO.... 
    INSERT INTO.... 
COMMIT TRANSACTION 
    PRINT 'Rows inserted successfully...' 

END TRY 

BEGIN CATCH 
    IF (@@TRANCOUNT > 0) 
    BEGIN 
     ROLLBACK TRANSACTION 
     PRINT 'Error detected, all changes reversed' 
    END 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber, 
     ERROR_SEVERITY() AS ErrorSeverity, 
     ERROR_STATE() AS ErrorState, 
     ERROR_PROCEDURE() AS ErrorProcedure, 
     ERROR_LINE() AS ErrorLine, 
     ERROR_MESSAGE() AS ErrorMessage 
END CATCH 
+0

मुझे लगता है कि आपके स्पष्टीकरण में '@@ TranCount' है, न कि' @@ रोकाउंट'। मैं एक सामान्य संदेश _ "सभी परिवर्तनों को उलट देता हूं" _ में शामिल करने में भी संकोच करता हूं क्योंकि वहां "खोए गए" पहचान मान, ट्रिगर्स के कारण दुष्प्रभाव हो सकते हैं ...। – HABO

0

मैं के बारे में प्रयास करें ... T-SQL में पकड़ने दो मन में कर रहा हूँ।

हालांकि यह भाषा के लिए संभावित रूप से उपयोगी अतिरिक्त है, तथ्य यह है कि यह उपलब्ध है हमेशा इसका उपयोग करने का एक कारण नहीं है।

अपने

DELETE FROM Table WHERE... 

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

उचित परीक्षण को देखते हुए, कोड और स्कीमा के बीच उस तरह की मेल-मिलाप इसे कभी भी उत्पादन में नहीं लेनी चाहिए। मान लीजिए कि यह करता है, "अशिष्ट" IMHO, अप्रत्याशित त्रुटि संदेश जिसके परिणामस्वरूप क्लाइंट पर लौटने के लिए एक चयन कथन में "विनम्र" रैपिंग से गलत हो गया है इसका एक बेहतर संकेत है। (जो कोशिश/squelch antipattern SeanLange उल्लेख करने के लिए राशि कर सकते हैं)।

अधिक जटिल परिदृश्यों के लिए, मैं TRY ... कैच के लिए उपयोग देख सकता हूं। हालांकि आईएमएचओ इनपुट पैरामीटर की सावधानीपूर्वक सत्यापन के लिए कोई विकल्प नहीं है।

1

मैं यहाँ एक सी # डेवलपर के रूप में मेरी परिप्रेक्ष्य देना चाहता हूँ:

ऊपर (बस एक स्क्रिप्ट से कुछ तालिकाओं में डालने) दिया सरल परिदृश्य में, वहाँ के रूप में, आज़माएं/कैच जोड़ने के लिए कोई कारण नहीं है यह लेनदेन के लिए कोई लाभ नहीं जोड़ता है। दोनों उदाहरण बिल्कुल वही परिणाम देंगे: या तो सभी टेबल डाले जाएंगे, या वे नहीं होंगे। डेटाबेस की स्थिति सुसंगत बनी हुई है।(चूंकि COMMIT ट्रांज़ेक्शन कभी नहीं कहा जाता है, इसलिए स्क्रिप्ट के अंत में रोलबैक को एसक्यूएल सर्वर द्वारा स्पष्ट रूप से बुलाया जाता है।)

हालांकि, कई बार आप कोशिश/पकड़ में चीजें कर सकते हैं जो एकीकृत के साथ संभव नहीं हैं गलती संभालना। उदाहरण के लिए, त्रुटि को एक त्रुटि तालिका में लॉगिंग करना।

मेरे सी # अनुभव में, एक कोशिश/कैच का उपयोग करने का एकमात्र समय तब होता है जब डेवलपर के नियंत्रण से बाहर की चीजें होती हैं, जैसे फ़ाइल खोलने का प्रयास करना। ऐसे मामले में, नेट फ्रेमवर्क द्वारा उत्पन्न अपवाद को प्रबंधित करने का एकमात्र तरीका Try/Catch के माध्यम से होता है।

अगर मैं संग्रहीत प्रक्रिया कर रहा था, और मैन्युअल रूप से डेटा की स्थिति जांचना चाहता था और मैन्युअल रूप से ROLLBACK TRANSACTION पर कॉल करना चाहता था, तो मैं उसे देख सकता था। लेकिन इसे अभी भी कोशिश/पकड़ की आवश्यकता नहीं होगी।

संबंधित मुद्दे