11

का निपटान करने के बाद अलगाव स्तर को वापस नहीं करता है मैं लेनदेन के क्षेत्र और इकाई ढांचे के साथ थोड़ा सा सरगर्मी कर रहा हूं।एंटीटी फ्रेमवर्क और ट्रांस्पेक्शनस्कोप लेनदेनकोप

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

हालांकि, समस्या यह है कि जब लेनदेन के दायरे का निपटारा किया जाता है, तो अलगाव अभी भी कनेक्शन पर बना रहता है, जिससे काफी समस्याएं होती हैं।

मैंने सभी प्रकार की विविधताओं का प्रयास किया है, लेकिन उसी परिणाम के साथ; अलगाव लेनदेन लेनदेन के दायरे से परे संरक्षित है।

क्या कोई ऐसा व्यक्ति है जो मेरे लिए इस व्यवहार को समझा सकता है या समझा सकता है कि मैं क्या गलत कर रहा हूं?

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

यहाँ एक examplecode है कि समस्या को दिखाता है:

using (var context = new MyContext()) 
{ 
    context.Database.Connection.Open(); 

    //Sets the connection to default read snapshot 
    using (var command = context.Database.Connection.CreateCommand()) 
    { 
     command.CommandText = "SET TRANSACTION ISOLATION LEVEL SNAPSHOT"; 
     command.ExecuteNonQuery(); 
    } 

    //Executes a DBCC USEROPTIONS to print the current connection information and this shows snapshot 
    PrintDBCCoptions(context.Database.Connection); 

    //Executes a query 
    var result = context.MatchTypes.ToArray(); 

    //Executes a DBCC USEROPTIONS to print the current connection information and this still shows snapshot 
    PrintDBCCoptions(context.Database.Connection); 

    using (var scope = new TransactionScope(TransactionScopeOption.Required, 
     new TransactionOptions() 
     { 
      IsolationLevel = IsolationLevel.ReadCommitted //Also tried ReadUncommitted with the same result 
     })) 
    { 
     //Executes a DBCC USEROPTIONS to print the current connection information and this still shows snapshot 
     //(This is ok, since the actual new query with the transactionscope isn't executed yet) 
     PrintDBCCoptions(context.Database.Connection); 
     result = context.MatchTypes.ToArray(); 
     //Executes a DBCC USEROPTIONS to print the current connection information and this has now changed to read committed as expected      
     PrintDBCCoptions(context.Database.Connection); 
     scope.Complete(); //tested both with and without 
    } 

    //Executes a DBCC USEROPTIONS to print the current connection information and this is still read committed 
    //(I can find this ok too, since no command has been executed outside the transaction scope) 
    PrintDBCCoptions(context.Database.Connection); 
    result = context.MatchTypes.ToArray(); 

    //Executes a DBCC USEROPTIONS to print the current connection information and this is still read committed 
    //THIS ONE is the one I don't expect! I expected that the islation level of my connection should revert here 
    PrintDBCCoptions(context.Database.Connection); 
} 
+1

कुछ उत्तरों में भी उल्लेख किया गया है [_here _] (http : //stackoverflow.com/questions/3759897/how-does-sqlconnection-manage-isolationlevel) और संभावित रूप से संबंधित [_Connect Bug_] (https://connect.microsoft.com/SQLServer/feedback/details/243527/sp- रीसेट-कनेक्शन-does not को रीसेट-अलगाव-स्तर)। – crokusek

उत्तर

18

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

मेरे मुद्दे पर्यावरण पर निर्भर होने के कई कारण हैं।

डेटाबेस सर्वर संस्करण:

सबसे पहले, आपरेशन के परिणाम (SQL सर्वर 2012 और SQL सर्वर 2014 को परीक्षण किया) आप चल रहे हैं एसक्यूएल सर्वर संस्करण पर निर्भर करता है।

एसक्यूएल सर्वर 2012

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

उदाहरण के लिए:

Console.WriteLine(context.MatchTypes.Where(mt => mt.Id == 2).Select(mt => mt.LastUpdated).First()); 

using (var scope = new TransactionScope(TransactionScopeOption.Required, 
             new TransactionOptions 
             { 
              IsolationLevel = IsolationLevel.ReadUncommitted 
             })) 
{ 
    Console.WriteLine(context.MatchTypes.Where(mt => mt.Id == 2) 
             .Select(mt => mt.LastUpdated).First()); 
    scope.Complete(); //tested both with and without 
} 

Console.WriteLine(context.MatchTypes.Where(mt => mt.Id == 2).Select(mt => mt.LastUpdated).First()); 

इस उदाहरण में, पहले एफई आदेश डेटाबेस डिफ़ॉल्ट, लेन-देन दायरे के भीतर एक ReadUncommitted के साथ चलेंगे, और तीसरा एक भी ReadUncommitted साथ चलेंगे साथ चलेंगे।

SQL सर्वर 2014

दूसरी ओर एसक्यूएल सर्वर 2014 को, प्रत्येक बार कोई कनेक्शन कनेक्शन पूल से प्राप्त किया जाता है sp_reset_connection प्रक्रिया (ऐसा लगता है कि यह इस एक वैसे भी है लगता है) अलगाव स्तर सेट हो जाएगा डेटाबेस पर डिफ़ॉल्ट पर वापस, भले ही कनेक्शन उसी लेनदेन के दायरे से पुनः प्राप्त हो। प्रयोग में; इसका अर्थ यह है कि यदि आपके पास एक लेन-देन का दायरा है जहां आप दो अनुवर्ती आदेशों को निष्पादित करते हैं तो पहले व्यक्ति को लेनदेन के दायरे का अलगाव स्तर मिल जाएगा। अच्छा भी नहीं; आप (डेटाबेस पर डिफ़ॉल्ट अलगाव स्तर के आधार पर) प्राप्त करेंगे या तो लॉक या स्नैपशॉट रीडिंग प्राप्त करेंगे।

उदाहरण के लिए:

Console.WriteLine(context.MatchTypes.Where(mt => mt.Id == 2).Select(mt => mt.LastUpdated).First()); 

using (var scope = new TransactionScope(TransactionScopeOption.Required, 
             new TransactionOptions 
             { 
              IsolationLevel = IsolationLevel.ReadUncommitted 
             })) 
{ 
    Console.WriteLine(context.MatchTypes.Where(mt => mt.Id == 2) 
          .Select(mt => mt.LastUpdated).First()); 
    Console.WriteLine(context.MatchTypes.Where(mt => mt.Id == 2) 
          .Select(mt => mt.LastUpdated).First()); 
    scope.Complete(); 
} 

इस उदाहरण में, पहले एफई आदेश डेटाबेस डिफ़ॉल्ट के साथ चलेंगे, लेन-देन के भीतर पहले एक ReadUncommitted साथ चलाया जाएगा, लेकिन एक दूसरे के दायरे के भीतर अचानक के रूप में चलेंगे डेटाबेस फिर से डिफ़ॉल्ट।

मैन्युअल खुले कनेक्शन मुद्दा:

वहाँ अन्य मुद्दों है कि एक मैन्युअल रूप से खुले कनेक्शन के साथ विभिन्न एसक्यूएल सर्वर संस्करण पर होता है, तथापि, हम कड़ाई से इस तो मैं नहीं जा रहा हूँ क्या करने की जरूरत नहीं है अब इस समस्या में रहने के लिए।

का उपयोग Database.BeginTransaction:

किसी कारण से, इकाई की रूपरेखा के Database.BeginTransaction तर्क दोनों डेटाबेस जो ठीक है में काम करने लगता है, लेकिन हमारे कोड में हम दो अलग डेटाबेस के विरुद्ध काम करता है और फिर हम लेनदेन के क्षेत्र की आवश्यकता है।

निष्कर्ष:

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

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

समाधान:

समाधान (जहाँ तक मैं आ गए हैं) इस तरह है।

आवश्यकताएं यहां इस समाधान होगा: 1. डेटाबेस MUST अलगाव अन्य अनुप्रयोगों के कारण स्तर है कि एक ही डेटाबेस है कि इस आवश्यकता के खिलाफ चलाता प्रतिबद्ध पढ़ा जा, हम पर कमिट स्नैपशॉट चूक पढ़ें उपयोग नहीं कर सकते डेटाबेस 2. हमारे आवेदन आवश्यक में स्नैपशॉट अलगाव स्तर का डिफ़ॉल्ट है - यह सेट ट्रांज़ेक्शन इस्लामीलेवल स्नैपशॉट 3 का उपयोग करके हल किया जाता है।अगर वहाँ एक लेन-देन गुंजाइश है, हम समाधान इस तरह होगा इस

तो इन criterias के आधार पर अलगाव के स्तर का सम्मान करने के लिए की जरूरत है:

संदर्भ निर्माता में, मैं जहां में StateChange घटना रजिस्टर मैं जब राज्य को ओपन में बदल दिया जाता है तो चालू हो जाता है और कोई सक्रिय लेनदेन क्लासिक ADO.NET का उपयोग करके स्नैपशॉट के अलगाव स्तर को डिफ़ॉल्ट करता है। यदि किसी लेन-देन के दायरे का उपयोग किया जाता है, तो हमें सेटिंग्स के आधार पर एसईटी ट्रांज़ेक्शन इस्लामीलेवल चलाने के द्वारा इसकी सेटिंग्स का सम्मान करने की आवश्यकता है (हमारे अपने कोड को सीमित करने के लिए, हम केवल पढ़ाए गए, पढ़ाए गए और स्नैपशॉट के अलगाव लेवल को अनुमति देंगे)। डाटाबेस द्वारा बनाए गए लेन-देन के लिए। संदर्भ पर बीजिनट्रांसेक्शन ऐसा लगता है कि इसे सम्मानित किया जाना चाहिए क्योंकि ऐसा होना चाहिए ताकि हम इन प्रकार के लेन-देन के साथ कोई विशेष कार्य न करें।

यहाँ संदर्भ में कोड है:

public MyContext() 
{ 
    Database.Connection.StateChange += OnStateChange; 
} 

protected override void Dispose(bool disposing) 
{ 
    if(!_disposed) 
    { 
     Database.Connection.StateChange -= OnStateChange; 
    } 

    base.Dispose(disposing); 
} 

private void OnStateChange(object sender, StateChangeEventArgs args) 
{ 
    if (args.CurrentState == ConnectionState.Open && args.OriginalState != ConnectionState.Open) 
    { 
     using (var command = Database.Connection.CreateCommand()) 
     { 
      if (Transaction.Current == null) 
      { 
       command.CommandText = "SET TRANSACTION ISOLATION LEVEL SNAPSHOT"; 
      } 
      else 
      { 
       switch (Transaction.Current.IsolationLevel) 
       { 
        case IsolationLevel.ReadCommitted: 
         command.CommandText = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED"; 
         break; 
        case IsolationLevel.ReadUncommitted: 
         command.CommandText = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"; 
         break; 
        case IsolationLevel.Snapshot: 
         command.CommandText = "SET TRANSACTION ISOLATION LEVEL SNAPSHOT"; 
         break; 
        default: 
         throw new ArgumentOutOfRangeException(); 
       } 
      } 

      command.ExecuteNonQuery(); 
     } 
    } 
} 

मैं दोनों एसक्यूएल सर्वर 2012 और 2014 में इस कोड का परीक्षण किया है और यह काम करने लगता है। यह सबसे अच्छा कोड नहीं है और इसकी सीमाएं हैं (उदाहरण के लिए यह प्रत्येक ईएफ निष्पादन के लिए हमेशा डेटाबेस के खिलाफ एक सेट ट्रांज़ेक्शन इस्लामीलेवल करेगा और इस प्रकार अतिरिक्त नेटवर्क यातायात जोड़ देगा।)

+0

आप वास्तव में इसके नीचे गए! अपने काम में नजर रखने के लिए बहुत ही रोचक और अच्छा है। फिर भी, मुझे समझ में नहीं आता कि वर्तमान में 'पढ़ा गया स्नैपशॉट' क्यों सर्वोत्तम अभ्यास माना जाता है, ताकि ईएफ ने इसे ईएफ 6 के बाद जेनरेट किए गए डेटाबेस के लिए डिफ़ॉल्ट के रूप में बदल दिया हो। इसके अलावा आप सभी कोड नमूने में एक ही संदर्भ के साथ काम करते प्रतीत होते हैं। क्या आप अलग-अलग संदर्भ उदाहरणों के साथ काम करते समय एक ही प्रभाव देखते हैं? –

+0

खैर, मैं वास्तव में इसे सबसे अच्छा अभ्यास नहीं मानता, लेकिन हमारा आवेदन कुछ लंबे समय तक चलने वाले लेनदेन (30 सेकंड) करता है जो एसीआईडी ​​होना चाहिए और इस समय के दौरान अन्य कनेक्शन जो एक ही डेटा के खिलाफ एक पढ़ी गई क्वेरी को 30 परिणाम प्राप्त करने से पहले सेकंड, जो उपयोगकर्ता के लिए स्वीकार्य नहीं है। परिणामस्वरूप अंतिम अंतिम डेटा होगा। हालांकि हालात हैं कि तर्क को वास्तव में नवीनतम डेटा की आवश्यकता है लेकिन गंदे पढ़ने की इच्छा नहीं है। इन परिस्थितियों में प्रतीक्षा करना स्वीकार्य है और हम प्रतीक्षा को लागू करने के लिए प्रतिबद्ध पढ़ने के साथ लेनदेन का उपयोग करते हैं। –

+1

विभिन्न संदर्भ उदाहरणों के लिए, हां। एसक्यूएल सर्वर 2012 के लिए यदि आप कनेक्शन सेटिंग का उपयोग करते हैं तो पिछले सेट अलगाव स्तर उसी कनेक्शन पर रहेगा जहां तक ​​मैं कह सकता हूं, जो मेरी राय में विनाशकारी है। मैंने जो समाधान पोस्ट किया है, वह इस व्यवहार को तब तक रोक देगा जब तक आप कनेक्शन मैन्युअल रूप से नहीं खोलते हैं और ईएफ को आपके लिए करते हैं। –

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