क्या मुझे पढ़ने के लिए लेनदेन करना चाहिए या रोलबैक करना चाहिए?


95

मेरे पास एक पढ़ने की क्वेरी है जिसे मैं एक लेनदेन के भीतर निष्पादित करता हूं ताकि मैं अलगाव स्तर को निर्दिष्ट कर सकूं। एक बार क्वेरी पूरी हो जाने के बाद, मुझे क्या करना चाहिए?

  • लेन-देन करें
  • लेन-देन रोलबैक करें
  • कुछ भी न करें (जिससे लेन-देन ब्लॉक के अंत में लेन-देन वापस हो जाएगा)

प्रत्येक करने के निहितार्थ क्या हैं?

using (IDbConnection connection = ConnectionFactory.CreateConnection())
{
    using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
    {
        using (IDbCommand command = connection.CreateCommand())
        {
            command.Transaction = transaction;
            command.CommandText = "SELECT * FROM SomeTable";
            using (IDataReader reader = command.ExecuteReader())
            {
                // Read the results
            }
        }

        // To commit, or not to commit?
    }
}

EDIT: प्रश्न यह नहीं है कि क्या लेन-देन का उपयोग किया जाना चाहिए या यदि लेनदेन स्तर निर्धारित करने के अन्य तरीके हैं या नहीं। सवाल यह है कि क्या इससे कोई फर्क पड़ता है कि कोई लेन-देन जो कुछ भी संशोधित नहीं करता है वह प्रतिबद्ध है या वापस लुढ़का हुआ है। क्या कोई प्रदर्शन अंतर है? क्या यह अन्य कनेक्शनों को प्रभावित करता है? कोई अन्य मतभेद?


1
आप शायद इस बारे में पहले से ही जानते हैं, लेकिन आपके द्वारा प्रदान किए गए उदाहरण को देखते हुए, आपके पास क्वेरी निष्पादित करने के लिए सरल परिणाम के बराबर परिणाम हो सकते हैं: NOLOCK के साथ कुछ का चयन करें *
जेसनट्रू

@Tefan, ऐसा लगता है कि हम में से अधिकांश को आश्चर्य होता है कि आप केवल रीड ऑपरेशन पर ही लेन-देन करने की जहमत क्यों उठा रहे हैं। क्या आप हमें बता सकते हैं कि क्या आप NOLOCK के बारे में जानते हैं और यदि आप ऐसा करते हैं, तो आप उस मार्ग पर क्यों नहीं गए।
स्टिंगजैक

मैं NOLOCK के बारे में जानता हूं, लेकिन यह सिस्टम अलग-अलग डेटाबेस के साथ-साथ SQL सर्वर पर भी काम करता है, इसलिए मैं SQL सर्वर विशिष्ट लॉकिंग संकेत से बचने की कोशिश कर रहा हूं। यह किसी और चीज की तुलना में अधिक जिज्ञासा का प्रश्न है क्योंकि आवेदन ऊपर दिए गए कोड के साथ ठीक काम कर रहा है।
स्टीफन मोजर

आह, उस मामले में मैं sqlserver टैग हटा रहा हूं, क्योंकि यह लक्ष्य उत्पाद के रूप में MSSqlServer को दर्शाता है।
स्टिंगजैक

@StingyJack - आप सही हैं, मुझे sqlserver टैग का उपयोग नहीं करना चाहिए था।
स्टीफन मोजर

जवाबों:


51

आप कमिट करें। अवधि। कोई अन्य समझदार विकल्प नहीं है। यदि आपने लेनदेन शुरू किया है, तो आपको इसे बंद कर देना चाहिए। आपके द्वारा किए गए किसी भी ताले को कमिट करना, और ReadUncommitted या Serializable अलगाव स्तरों के साथ समान रूप से समझदार है। निहित रोलबैक पर भरोसा करते हुए - जबकि तकनीकी रूप से समतुल्य - केवल खराब रूप है।

अगर इससे आपको यकीन नहीं होता है, तो बस अगले आदमी की कल्पना करें जो आपके कोड के बीच में एक अपडेट स्टेटमेंट डालता है, और उसके डेटा को निकालने और उसके डेटा को निकालने के लिए नीचे दिए गए रोलबैक को ट्रैक करना होगा।


44
एक समझदार विकल्प है - रोलबैक। स्पष्ट रोलबैक, अर्थात्। यदि आपको कुछ भी बदलने का मतलब नहीं है, तो रोलबैक यह सुनिश्चित करता है कि कुछ भी पूर्ववत नहीं है। बेशक, कोई बदलाव नहीं होना चाहिए था; रोलबैक गारंटी देता है कि।
जोनाथन लेफ़लर

2
अलग-अलग डीबीएमएस में अलग-अलग 'निहित लेनदेन पूर्ण' शब्दार्थ हो सकते हैं। IBM Informix (और मेरा मानना ​​है कि DB2) निहित रोलबैक करता है; अफवाह से, ओरेकल एक निहित प्रतिबद्ध करता है। मैं निहित रोलबैक पसंद करता हूं।
जोनाथन लेफ्लर

8
मान लीजिए कि मैं एक अस्थायी तालिका बनाता हूं, इसे आईडी के साथ पॉप्युलेट करता हूं, डेटा तालिका के साथ जुड़कर उस डेटा का चयन करता हूं जो आईडी के साथ जाता है, फिर अस्थायी तालिका हटाएं। मैं वास्तव में सिर्फ डेटा पढ़ रहा हूं, और मुझे परवाह नहीं है कि अस्थायी तालिका का क्या होता है, क्योंकि यह अस्थायी है ... लेकिन प्रदर्शन के दृष्टिकोण से, क्या लेनदेन को रोलबैक करना या इसे कम करना अधिक महंगा होगा? जब कोई टेम्‍प टेबल और रीड ऑपरेशंस शामिल न हों तो कमिट / रोलबैक का क्‍या प्रभाव पड़ता है?
त्रिंको

4
@ ट्रायनको - सहज रूप से, मुझे लगता है कि रोलबैक अधिक महंगा है। COMMIT सामान्य उपयोग का मामला है, और असाधारण केस रोलआउट। लेकिन, अकादमिक को छोड़कर, कौन परवाह करता है? मुझे यकीन है कि आपके ऐप के लिए 1000 बेहतर अनुकूलन बिंदु हैं। यदि आप वास्तव में उत्सुक हैं, तो आप bSQL.launchpad.net/~mysql/mysql-server/mysql-6.0/annotate/…
मार्क

3
@ ट्रायनको - ऑप्टिमाइज़ करने का एकमात्र तरीका प्रोफ़ाइल है। यह इतना सरल कोड परिवर्तन है, दोनों तरीकों को प्रोफाइल करने का कोई कारण नहीं है यदि आप वास्तव में इसे अनुकूलित करना चाहते हैं। परिणामों के साथ हमें अपडेट करना सुनिश्चित करें!
मार्क ब्रैकेट

28

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


2
मुझे यह बताने के लिए धन्यवाद कि वे समकक्ष हैं। मेरी राय में, यह सबसे अच्छा प्रश्न है।
चौबे

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

6

यदि आप एक लेनदेन शुरू करते हैं, तो सबसे अच्छा अभ्यास हमेशा इसे करने के लिए होता है। यदि कोई अपवाद आपके उपयोग (लेन-देन) के अंदर फेंक दिया जाता है, तो लेनदेन स्वचालित रूप से रोल-बैक हो जाएगा।


3

IMHO यह केवल लेन-देन में प्रश्नों को पढ़ने के लिए समझ में आता है (विशेष रूप से जावा में) आप लेन-देन को "केवल पढ़ने के लिए" बता सकते हैं जो बदले में जेडीबीसी चालक क्वेरी को अनुकूलित करने पर विचार कर सकता है (लेकिन इसके लिए नहीं है, इसलिए कोई भी नहीं आपको INSERTफिर भी जारी करने से रोकेगा )। उदाहरण के लिए ओरेकल ड्राइवर रीड-ओनली चिह्नित किए गए लेन-देन में प्रश्नों पर टेबल लॉक से पूरी तरह से बच जाएगा, जो कि भारी रीड-चालित अनुप्रयोगों पर बहुत अधिक प्रदर्शन प्राप्त करता है।


3

नेस्टेड लेनदेन पर विचार करें

अधिकांश RDBMSes नेस्टेड लेनदेन का समर्थन नहीं करते हैं, या बहुत सीमित तरीके से उनका अनुकरण करने की कोशिश करते हैं।

उदाहरण के लिए, MS SQL सर्वर में, एक आंतरिक लेनदेन में रोलबैक (जो कि वास्तविक लेनदेन नहीं है, MS SQL सर्वर लेन-देन के स्तर की गणना करता है!) जो कुछ भी बाहरी रूप से हुआ है उसे रोलबैक करेगा। लेनदेन (जो कि वास्तविक लेनदेन है) ।

कुछ डेटाबेस रैपर आंतरिक लेन-देन में रोलबैक पर विचार कर सकते हैं एक संकेत के रूप में कि एक त्रुटि हुई है और बाहरी लेन-देन में सब कुछ रोलबैक किया गया है, भले ही बाहरी लेनदेन शुरू हो या वापस रोल किया गया हो।

तो एक COMMIT एक सुरक्षित तरीका है, जब आप यह नहीं बता सकते कि आपके घटक का उपयोग कुछ सॉफ्टवेयर मॉड्यूल द्वारा किया जाता है।

कृपया ध्यान दें कि यह प्रश्न का सामान्य उत्तर है। कोड उदाहरण चतुराई से एक नया डेटाबेस कनेक्शन खोलकर बाहरी लेनदेन के साथ समस्या के आसपास काम करता है।

प्रदर्शन के बारे में: अलगाव स्तर के आधार पर, SELECTs को अलग-अलग डिग्री के LOCKs और अस्थायी डेटा (स्नैपशॉट) की आवश्यकता हो सकती है। लेन-देन बंद होने पर यह साफ हो जाता है। इससे कोई फर्क नहीं पड़ता कि यह COMMIT या रोलबैक के माध्यम से किया गया है। खर्च किए गए CPU समय में एक महत्वहीन अंतर हो सकता है - एक COMMIT संभवतः एक ROLLBACK (दो वर्ण कम) और अन्य मामूली अंतरों की तुलना में पार्स करने के लिए तेज़ है। जाहिर है, यह केवल पढ़ने-लिखने के लिए ही सही है!

पूरी तरह से नहीं पूछा गया: एक अन्य प्रोग्रामर जो कोड को पढ़ने के लिए प्राप्त कर सकता है वह मान सकता है कि एक रोलबैक का अर्थ एक त्रुटि स्थिति है।


2

बस एक साइड नोट, लेकिन आप उस कोड को इस तरह भी लिख सकते हैं:

using (IDbConnection connection = ConnectionFactory.CreateConnection())
using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
using (IDbCommand command = connection.CreateCommand())
{
    command.Transaction = transaction;
    command.CommandText = "SELECT * FROM SomeTable";
    using (IDataReader reader = command.ExecuteReader())
    {
        // Do something useful
    }
    // To commit, or not to commit?
}

और अगर आप चीजों को थोड़ा-सा ही री-स्ट्रक्चर करते हैं, तो हो सकता है कि आप IDataReader के लिए उपयोग करने वाले ब्लॉक को ऊपर तक ले जा सकें।


1

यदि आप SQL को संग्रहीत कार्यविधि में रखते हैं और इसे क्वेरी से ऊपर जोड़ते हैं:

set transaction isolation level read uncommitted

फिर आपको C # कोड में किसी भी हूप से कूदना नहीं है। एक संग्रहीत कार्यविधि में लेन-देन अलगाव स्तर सेट करना उस कनेक्शन के सभी भविष्य के उपयोगों के लिए सेटिंग को लागू करने का कारण नहीं बनता है (जो कि कुछ चीजें आपको अन्य सेटिंग्स के बारे में चिंता करना है क्योंकि कनेक्शन पूल किए जाते हैं)। संग्रहीत कार्यविधि के अंत में यह केवल उस कनेक्शन पर आरंभिक रूप से वापस चला जाता है, जिसके साथ कनेक्शन किया गया था।


1

रोलबैक का उपयोग ज्यादातर एक त्रुटि या असाधारण परिस्थितियों के मामले में किया जाता है, और सफल समापन के मामले में COMMIT।

हमें COMMIT (सफलता के लिए) और ROLLBACK (विफलता के लिए) के साथ लेन-देन बंद करना चाहिए, यहां तक ​​कि केवल-पढ़ने के लिए लेन-देन के मामले में जहां यह मामला नहीं लगता है। वास्तव में यह मायने रखता है, निरंतरता और भविष्य के प्रमाण के लिए।

एक रीड-ओनली ट्रांजेक्शन तार्किक रूप से "विफल" हो सकता है, उदाहरण के लिए:

  • एक क्वेरी अपेक्षा के अनुरूप एक पंक्ति में वापस नहीं आती है
  • एक संग्रहीत प्रक्रिया एक अपवाद उठाती है
  • पाया गया डेटा असंगत पाया जाता है
  • उपयोगकर्ता लेन-देन निरस्त करता है क्योंकि इसमें बहुत अधिक समय लग रहा है
  • गतिरोध या समय समाप्त

यदि COMMIT और ROLLBACK का उपयोग केवल पढ़ने-योग्य लेन-देन के लिए किया जाता है, तो यह अपेक्षित रूप से कार्य करना जारी रखेगा यदि DB बिंदु कोड को किसी बिंदु पर जोड़ा जाता है, जैसे कैशिंग, ऑडिटिंग या आँकड़े।

इम्प्लिक्ट रोलबैक का उपयोग केवल "घातक त्रुटि" स्थितियों के लिए किया जाना चाहिए, जब एप्लिकेशन क्रैश हो जाता है या एक अपरिवर्तनीय त्रुटि, नेटवर्क विफलता, बिजली की विफलता, आदि से बाहर निकलता है।


0

यह देखते हुए कि एक READ राज्य नहीं बदलता है, मैं कुछ नहीं करूँगा। डेटाबेस के लिए अनुरोध भेजने के लिए एक चक्र बर्बाद करने के अलावा, एक प्रतिबद्ध प्रदर्शन करना कुछ भी नहीं करेगा। आपने एक ऑपरेशन नहीं किया है जिसने राज्य को बदल दिया है। इसी तरह रोलबैक के लिए।

हालांकि, आपको अपनी वस्तुओं को साफ करना और डेटाबेस से अपने कनेक्शन बंद करना सुनिश्चित करना चाहिए। यदि आपके कोड को बार-बार कॉल किया जाता है, तो आपके कनेक्शन बंद नहीं करने से समस्याएं हो सकती हैं।


3
अलगाव स्तर के आधार पर, एक चुनिंदा ताले को प्राप्त कर सकता है जो अन्य लेनदेन को रोक देगा।
ग्रीम पेरो

उपयोग ब्लॉक के अंत में कनेक्शन बंद कर दिया जाएगा- यही वह है जिसके लिए यह है। लेकिन अच्छी बात यह है कि नेटवर्क ट्रैफ़िक शायद समीकरण का सबसे धीमा हिस्सा है।
जोएल कोएहॉर्न

1
लेन-देन को प्रतिबद्ध या एक तरह से या किसी अन्य तरीके से वापस रोल किया जाएगा, इसलिए सबसे अच्छा अभ्यास हमेशा एक प्रतिबद्ध जारी करना होगा अगर यह सफल हुआ।
नील बर्नवेल

0

यदि आप AutoCommit को गलत सेट करते हैं, तो हाँ।

JDBC (Postgresql ड्राइवर) के साथ एक प्रयोग में, मैंने पाया कि यदि क्वेरी ब्रेक (टाइमआउट के कारण) का चयन करती है, तो आप तब तक नई चयन क्वेरी शुरू नहीं कर सकते जब तक आप रोलबैक नहीं करते।


-2

आपके कोड नमूने में, आपके पास कहाँ है

  1. // कुछ उपयोगी

    क्या आप SQL कथन निष्पादित कर रहे हैं जो डेटा को बदलता है?

यदि नहीं, तो "पढ़ें" लेन-देन जैसी कोई चीज नहीं है ... केवल एक इन्सर्ट, अपडेट और डिलीट स्टेटमेंट्स (स्टेटमेंट्स जो डेटा बदल सकते हैं) से एक ट्रांजेक्शन में हैं ... आप जिस बारे में बात कर रहे हैं वह है SQL सर्वर उस डेटा को डालता है जिसे आप पढ़ रहे हैं, क्योंकि अन्य लेनदेन जो उस डेटा को प्रभावित करते हैं। इन तालों का स्तर SQL सर्वर अलगाव स्तर पर निर्भर है।

लेकिन अगर आपका SQL स्टेटमेंट कुछ भी नहीं बदला है, तो आप कुछ भी कमिट नहीं कर सकते या वापस नहीं कर सकते।

यदि आप डेटा बदल रहे हैं, तो आप स्पष्ट रूप से एक ट्रांज़िशन शुरू किए बिना आइसोलेशन स्तर को बदल सकते हैं ... प्रत्येक व्यक्ति का एसक्यूएल स्टेटमेंट स्पष्ट रूप से लेनदेन में है। स्पष्ट रूप से एक लेनदेन शुरू करना केवल यह सुनिश्चित करने के लिए आवश्यक है कि 2 या अधिक स्टेटमेंट एक ही लेनदेन के भीतर हैं।

यदि आप सभी लेन-देन अलगाव स्तर सेट करना चाहते हैं, तो बस एक कमांड के कमांडटैट को "सेट करें ट्रांजेक्शन अलगाव स्तर रिपीटेबल रीड" (या जो भी स्तर आप चाहते हैं) सेट करें, कमांड टाइप करें कमांडटाइप.टेक्स्ट पर सेट करें, और कमांड निष्पादित करें। (आप Command.ExecuteNonQuery () का उपयोग कर सकते हैं)

नोट: यदि आप MULTIPLE स्टेटमेंट पढ़ रहे हैं, और चाहते हैं कि सभी पहले वाले के समान डेटाबेस की "स्थिति" को "देखें", तो आपको आइसोलेशन लेवल के टॉप रिपीटेबल रीड या सीरियल को सेट करना होगा ...


// कुछ उपयोगी करने से कोई डेटा नहीं बदलता है, बस पढ़ें। मैं केवल इतना करना चाहता हूं कि क्वेरी के अलगाव स्तर को निर्दिष्ट करें।
स्टीफन मोजर

तब आप ऐसा कर सकते हैं कि स्पष्ट रूप से ग्राहक से लेन-देन शुरू किए बिना ... बस sql string निष्पादित करें "Transaction Isolation Level ReadUncommitted", "... Read Committed", "... repeatableRead", "... Snapshot" को निष्पादित करें। , या "... सीरियल करने योग्य" "सेट अलगाव का स्तर पढ़ें
कमिटेड

3
लेन-देन अभी भी मायने रखता है भले ही आप केवल पढ़ रहे हों। यदि आप कई रीड ऑपरेशंस करना चाहते हैं, तो उन्हें ट्रांजेक्शन के अंदर करने से स्थिरता सुनिश्चित होगी। एक के बिना उन्हें करना नहीं होगा।
MarkR

हाँ क्षमा करें, आप सही हैं, कम से कम यह सच है अगर अलगाव स्तर रिपीटेबल रीड या उच्च पर सेट है।
चार्ल्स ब्रेटाना

-3

क्या आपको उसी डेटा को पढ़ने से दूसरों को ब्लॉक करने की आवश्यकता है? लेन-देन का उपयोग क्यों करें?

@Joel - मेरा प्रश्न बेहतर होगा कि "रीड क्वेरी पर लेन-देन का उपयोग क्यों करें?"

@Stefan - यदि आप AdHoc SQL का उपयोग करने जा रहे हैं और एक संग्रहित खरीद नहीं है, तो क्वेरी में तालिकाओं के बाद केवल बिना (NOLOCK) जोड़ें। इस तरह आप आवेदन में ओवरहेड (यद्यपि न्यूनतम) और डेटाबेस के लिए लेनदेन के लिए नहीं करते हैं।

SELECT * FROM SomeTable WITH (NOLOCK)

संपादित करें @ टिप्पणी 3: चूंकि आपके पास प्रश्न टैग में "sqlserver" था, मैंने मान लिया था कि MSSQLServer लक्ष्य उत्पाद था। अब उस बिंदु को स्पष्ट कर दिया गया है, मैंने विशिष्ट उत्पाद संदर्भ को हटाने के लिए टैग संपादित किए हैं।

मुझे अभी भी यकीन नहीं है कि आप पहली बार रीड ओप पर लेन-देन क्यों करना चाहते हैं।


1
एक ही बार में अलगाव स्तर सेट करने के लिए। आप वास्तव में क्वेरी के लिए लॉकिंग की मात्रा को कम करने के लिए लेनदेन का उपयोग कर सकते हैं ।
जोएल कोएहॉर्न

1
मैं लेन-देन का उपयोग कर रहा हूं ताकि मैं कम अलगाव स्तर का उपयोग कर सकूं और लॉकिंग कम कर सकूं।
स्टीफन मोजर

@StingyJack - यह कोड कई अलग-अलग डेटाबेस के खिलाफ निष्पादित कर सकता है, इसलिए NOLOCK एक विकल्प नहीं है।
स्टीफन मोजर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.