2010-07-06 17 views
15

मेरे पास एक मूल वस्तु (एक डीएएल का हिस्सा) है जिसमें अन्य चीजों के साथ, बाल वस्तुओं के संग्रह (List<t>) शामिल हैं।लेनदेनस्कोप: वितरित लेनदेन से बचें

जब मैं ऑब्जेक्ट को डीबी पर वापस सहेज रहा हूं, तो मैं अभिभावक को दर्ज/अपडेट करता हूं, और फिर प्रत्येक बच्चे के माध्यम से लूप करता हूं। रखरखाव के लिए, मैंने बच्चे के लिए सभी कोड एक अलग निजी विधि में डाल दिया है।

मैं मानक एडीओ लेनदेन का उपयोग करने जा रहा था, लेकिन मेरी यात्रा पर, मैंने ट्रांज़ेक्शनस्कोप ऑब्जेक्ट में ठोकर खाई, जो मुझे विश्वास है कि मुझे मूल विधि में सभी डीबी इंटरैक्शन को लपेटने में सक्षम बनाता है (बाल विधि में सभी बातचीत के साथ) एक लेनदेन में।

अभी तक इतना अच्छा ..?

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

क्या मामला है? या यह है, जैसा कि मैं कहीं और पढ़ रहा हूं, एक मामला जो एक ही कनेक्शन स्ट्रिंग का उपयोग कर रहा है (जो खुद को कनेक्शन पूलिंग में उधार देगा) ठीक होगा?

अधिक व्यावहारिक रूप से बोल रहा है, मैं ...

  1. माता पिता & बच्चे में अलग कनेक्शन बनाएं (एक ही कनेक्शन स्ट्रिंग के साथ यद्यपि)
  2. माता पिता में एक कनेक्शन बनाएँ एक एक के रूप में यह माध्यम से पारित पैरामीटर (मुझे बेकार लगता है)
  3. कुछ और करें ...?

अद्यतन:

हालांकि यह प्रतीत होता है कि मैं का उपयोग कर मेरी हमेशा की तरह .NET3.5 + और एसक्यूएल सर्वर 2008 + ठीक हो सकता है, इस परियोजना के दूसरे हिस्से ओरेकल (10g) तो मैं का उपयोग किया जाएगा एक तकनीक का अभ्यास भी कर सकते हैं जिसे परियोजनाओं में लगातार इस्तेमाल किया जा सकता है।

तो मैं बस बाल विधियों के माध्यम से कनेक्शन पास कर दूंगा।


विकल्प 1 कोड नमूना:

using (TransactionScope ts = new TransactionScope()) 
      { 
       using (SqlConnection conn = new SqlConnection(connString)) 
       { 
        using (SqlCommand cmd = new SqlCommand()) 
        { 
         cmd.Connection = conn; 
         cmd.Connection.Open(); 
         cmd.CommandType = CommandType.StoredProcedure; 

         try 
         { 
          //create & add parameters to command 

          //save parent object to DB 
          cmd.ExecuteNonQuery(); 

          if ((int)cmd.Parameters["@Result"].Value != 0) 
          { 
           //not ok 
           //rollback transaction 
           ts.Dispose(); 
           return false; 
          } 
          else //enquiry saved OK 
          { 
           if (update) 
           { 
            enquiryID = (int)cmd.Parameters["@EnquiryID"].Value; 
           } 

           //Save Vehicles (child objects) 
           if (SaveVehiclesToEPE()) 
           { 
            ts.Complete(); 
            return true; 
           } 
           else 
           { 
            ts.Dispose(); 
            return false; 
           } 
          } 
         } 
         catch (Exception ex) 
         { 
          //log error 
          ts.Dispose(); 
          throw; 
         } 
        } 
       } 
      } 
+3

देखें [ट्रांज़ेक्शनस्कोप स्वचालित रूप से कुछ मशीनों पर एमएसडीटीसी में बढ़ रहा है?] (Http://stackoverflow.com/questions/1690892/transactionscope-automatically-escalating-to-msdtc-on-some-machines/1693795#1693795)। कई अच्छे उत्तर हैं, लेकिन जो मैंने लिंक किया है वह सबसे संक्षिप्त (और आपके प्रश्न के लिए प्रासंगिक है)। उपरोक्त यह है कि, यदि आप .NET 2.0 और SQL Server 2005 का उपयोग कर रहे हैं, तो आप एक ही कनेक्शन स्ट्रिंग वाले दो कनेक्शन का उपयोग करके भी बढ़ेंगे। यह .NET 3.5 और SQL Server 2008 के साथ कोई समस्या नहीं है। –

+0

मैं * .NET 3.5/4 और SQL 2008 का उपयोग कर रहा हूं, लेकिन कभी-कभी मैं SQL2005/2000 का उपयोग कर सकता हूं, इसलिए वैसे भी याद रखना उचित है। धन्यवाद – CJM

+0

क्या कोई मुझे वितरित लेनदेन के बारे में कुछ जानकारी दे सकता है। उदाहरण के साथ समझाओ। – Thomas

उत्तर

24

कई डेटाबेस एडीओ प्रदाताओं (जैसे ओरेकल ओडीपी.नेट) वास्तव में वितरित लेनदेन शुरू करते हैं जब आप TransactionScope का उपयोग कई कनेक्शनों में पारगमन करने के लिए करते हैं - भले ही वे समान कनेक्शन स्ट्रिंग साझा करते हैं।

कुछ प्रदाताओं, (जैसे .NET 3.5+ में SQL2008) पहचानता है कि एक लेनदेन क्षेत्र में एक नया कनेक्शन बनाया जाता है जो समान कनेक्शन स्ट्रिंग को संदर्भित करता है, और परिणामस्वरूप डीटीसी काम नहीं करेगा। लेकिन कनेक्शन स्ट्रिंग (जैसे ट्यूनिंग पैरामीटर) में कोई भी भिन्नता इसे होने से रोक सकती है - और व्यवहार एक वितरित लेनदेन का उपयोग करने के लिए वापस आ जाएगा।

दुर्भाग्य से, आपके लेनदेन को सुनिश्चित करने का एकमात्र विश्वसनीय माध्यम एक ही लेनदेन पर "जारी रखने" की आवश्यकता वाले तरीकों से कनेक्शन ऑब्जेक्ट (या IDbTransaction) को पास करने के लिए एक साथ लेनदेन लेनदेन बनाने के बिना काम करेगा।

कभी-कभी यह उस वर्ग के सदस्य को कनेक्शन को बढ़ाने में मदद करता है जिसमें आप काम कर रहे हैं, लेकिन यह अजीब परिस्थितियों को बना सकता है - और कनेक्शन ऑब्जेक्ट के जीवनकाल और निपटान को नियंत्रित करने में जटिल बनाता है (क्योंकि यह आम तौर पर उपयोग को रोकता है using कथन का)।

+0

मैं इस धारणा के तहत था कि कनेक्शन को कवर करने के लिए लेनदेनस्कोप के भीतर कनेक्शन बनाना होगा। मैं अनुमान लगा रहा हूं कि कनेक्शन के माध्यम से बस कुछ अन्य कामकाज की तुलना में सरल और सरल है? – CJM

+0

क्या आप जानते हैं कि यह ओरेकल 12 सी के साथ बदल गया है या नहीं? मुझे यह "ओडीएसी 12 सी या बाद में उपलब्ध" के रूप में चिह्नित किया गया है। यहां: https://apex.oracle.com/pls/apex/f?पी = 18357: 3 9: 1473540763666 :: नहीं :: पी 3 9_आईडी: 27121 – pauloya

1

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

अपडेट: कभी भी ध्यान न दें कि मैंने केवल बाल कॉल देखा है। इस स्थिति में, आप कनेक्शन ऑब्जेक्ट को बाल कक्षाओं में पास कर सकते हैं। इसके अलावा, आपको ट्रांज़ेक्शनस्कोप को मैन्युअल रूप से निपटाने की आवश्यकता नहीं है - ब्लॉकों का उपयोग करके प्रयास करें जैसे अंततः ब्लॉक करें और अपवादों पर भी निपटान निष्पादित करेंगे।

अपडेट 2: अभी तक बेहतर है, बच्चे वर्ग में आईडीबीट्रांसेंस पास करें। उस से कनेक्शन को पुनर्प्राप्त किया जा सकता है।

+0

हां, मुझे समझ में आया कि निपटान की स्पष्ट रूप से आवश्यकता नहीं थी, लेकिन जब मैं अपने कोड पर ट्रांज़ेक्शनस्कोप को दोबारा हटा देता हूं, तो मैं स्पष्ट रूप से भूल जाता हूं और अपने पुराने trm को परिवर्तित करना जारी रखता हूं। टोलबैक स्टेटमेंट्स को टी के बिना सोचें। अच्छी जगह! – CJM

+0

पुन ** अपडेट 2 ** - आप केवल 'आईडीबीकनेक्शन' को बाल वर्ग में पास कर सकते हैं। यदि आप 'IbConnection.BeginTransaction()' का उपयोग करते हैं, तो 'IDbConnection.CreateCommand()' के साथ बनाए गए सभी आदेश स्वचालित रूप से लेनदेन से जुड़े होंगे। यह बेहतर है क्योंकि यह आपके विरासत को पार करने के लिए एक कम पैरामीटर है, और युग्मन को कम करता है क्योंकि बाल कक्षाओं को इस बात से चिंतित होने की आवश्यकता नहीं होगी कि वे लेनदेन के भीतर निष्पादित हैं या नहीं। –

2

अनुभव से, मैं निर्धारित किया है कि (SQL सर्वर प्रदाता के लिए) अगर प्रक्रिया माता-पिता और बच्चे प्रक्रियाओं के बीच कनेक्शन (और लेन-देन) साझा करने के लिए पूलिंग कनेक्शन का लाभ ले सकते हैं, डीटीसी जरूरी हो गया है नहीं होगा शामिल।

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

ऐसा लगता है कि इस परिदृश्य से बचने के लिए आपके कोड को दोबारा प्रतिक्रिया देना आसान होगा: बाल प्रक्रियाओं का आह्वान करने से पहले पैरेंट प्रक्रिया द्वारा बनाए गए कनेक्शन को बंद करें।

+0

क्या आप कह रहे हैं कि अगर मैं कनेक्शन ऑब्जेक्ट से गुज़रता हूं, तो मुझे बच्चे में बंद होना चाहिए और बच्चे में फिर से खोलना होगा? – CJM

+0

नहीं। मुझे लगता है कि लेनदेन को वितरित लेनदेन में बढ़ावा देने के बिना आप लेनदेनस्कोप की सुविधा का लाभ उठाने का प्रयास कर रहे थे। ऐसा लगता है कि ओरेकल डेटाबेस को लक्षित करते समय यह संभव नहीं है, लेकिन यह SQL सर्वर डेटाबेस को लक्षित करना संभव है ... जब तक कनेक्शन को पूल किया जा सके और एक समय में केवल एक खुला कनेक्शन हो। –

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