NOLOCK के साथ एंटिटी फ्रेमवर्क


138

मैं NOLOCKएंटिटी फ्रेमवर्क पर फ़ंक्शन का उपयोग कैसे कर सकता हूं ? क्या XML ऐसा करने का एकमात्र तरीका है?

जवाबों:


207

नहीं, लेकिन आप एक लेनदेन शुरू कर सकते हैं और बिना पढ़े अलगाव स्तर निर्धारित कर सकते हैं । यह अनिवार्य रूप से NOLOCK के समान है, लेकिन इसे प्रति तालिका के आधार पर करने के बजाय, यह लेनदेन के दायरे में सब कुछ के लिए करेगा।

यदि आपको लगता है कि आप क्या चाहते हैं, तो यहां बताया गया है कि आप इसे कैसे कर सकते हैं ...

//declare the transaction options
var transactionOptions = new System.Transactions.TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new System.Transactions.TransactionScope(
    System.Transactions.TransactionScopeOption.Required, 
    transactionOptions)
)

//declare our context
using (var context = new MyEntityConnection())
{
    //any reads we do here will also read uncomitted data
    //...
    //...
    //don't forget to complete the transaction scope
    transactionScope.Complete();
}

उत्कृष्ट @DoctaJonez क्या इसके लिए EF4 में कुछ नया पेश किया गया था?
FMFF

@FMFF मुझे नहीं पता कि ईएफ 4 के लिए कुछ नया पेश किया गया था या नहीं। मुझे पता है कि उपरोक्त कोड EFv1 और इसके बाद के संस्करण के साथ काम करता है।
डॉक्टर जोन्स

इसका परिणाम क्या होगा? अगर किसी ने लेनदेन को छोड़ दिया है। क्या आपको लगता है कि मुझे इसके लिए एक और सवाल दायर करना चाहिए?
एकन गोपालकृष्णन १२'१५ को

@EanGopalakrishnan इस पद्धति को कॉल करने में विफल होने से लेन-देन समाप्त हो जाता है, क्योंकि लेनदेन प्रबंधक इसे सिस्टम विफलता के रूप में व्याख्या करता है, या अपवाद लेनदेन के दायरे में फेंका जाता है। (MSDN msdn.microsoft.com/en-us/library/… से लिया गया )
डॉक्टर जोन्स

1
@JsonStatham को इस पुल अनुरोध में जोड़ा गया है , जो कि मील के पत्थर के लिए है 2.1.0
डॉक्टर जोन्स

83

एक्सटेंशन के तरीके इसे आसान बना सकते हैं

public static List<T> ToListReadUncommitted<T>(this IQueryable<T> query)
{
    using (var scope = new TransactionScope(
        TransactionScopeOption.Required, 
        new TransactionOptions() { 
            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
    {
        List<T> toReturn = query.ToList();
        scope.Complete();
        return toReturn;
    }
}

public static int CountReadUncommitted<T>(this IQueryable<T> query)
{
    using (var scope = new TransactionScope(
        TransactionScopeOption.Required, 
        new TransactionOptions() { 
            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
    {
        int toReturn = query.Count();
        scope.Complete();
        return toReturn;
    }
}

मेरे प्रोजेक्ट में इसका उपयोग करने से कनेक्शन पूल पूरी तरह से अपवाद के रूप में उपयोग किया जाता है। पता नहीं क्यों कर सकते हैं। किसी और को इस मुद्दे को होने? कोई सुझाव?
बेन टिडमैन

1
कोई समस्या नहीं, बेन, अपने कनेक्शन के संदर्भ को अलग करने के लिए मत भूलना।
अलेक्जेंड्रे

एक संभावित कारण के रूप में लेनदेन के दायरे को बाहर करने के लिए समस्या को कम करने में सक्षम था। धन्यवाद। मेरे कंस्ट्रक्टर में कुछ कनेक्शन रिट्री स्टफ के साथ करना था।
बेन टिडमैन

मेरा मानना ​​है कि दायरा TransactionScopeOption.Suppress होना चाहिए
CodeGrue

@Alexandre क्या होगा अगर मैं एक और ReadCommitted लेनदेन के भीतर यह किया है? उदाहरण के लिए, मैंने डेटा सहेजना शुरू करने के लिए एक लेन-देन को जन्म दिया है, लेकिन अब मैं अधिक डेटा क्वेरी कर रहा हूं और इसलिए एक ReadUncommitted लेन-देन के भीतर पैदा कर रहा हूं? क्या इस "पूर्ण" कॉलिंग से मेरा बाहरी लेनदेन भी पूरा होगा? कृपया सलाह दें :)
जेसन लोकी स्मिथ

27

यदि आपको बड़े पैमाने पर किसी चीज की आवश्यकता है, तो सबसे अच्छा तरीका जो हमने पाया है कि वास्तव में हर बार लेनदेन शुरू करने की तुलना में कम घुसपैठ है, बस इस साधारण कमांड को चलाकर अपनी वस्तु संदर्भ तैयार करने के बाद अपने कनेक्शन पर डिफ़ॉल्ट लेनदेन अलगाव स्तर निर्धारित करना है:

this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");

http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx

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


2
लेन-देन अलगाव स्तर को अकेले निर्धारित करने से कोई प्रभाव नहीं पड़ेगा। आपको वास्तव में इसके लिए लेन-देन के भीतर चलने की आवश्यकता है ताकि इसका कोई प्रभाव न हो। READ UNCOMMITTED राज्यों के लिए MSDN प्रलेखन Transactions running at the READ UNCOMMITTED level do not issue shared locks। इसका तात्पर्य यह है कि लाभ पाने के लिए आपको लेनदेन के भीतर चलना चाहिए। ( msdn.microsoft.com/en-gb/library/ms173763.aspx से लिया गया )। आपका दृष्टिकोण कम घुसपैठ वाला हो सकता है, लेकिन यदि आप लेनदेन का उपयोग नहीं करते हैं तो यह कुछ भी हासिल नहीं करेगा।
डॉक्टर जोन्स

3
MSDN दस्तावेज़ीकरण कहता है: "SQL सर्वर से कनेक्शन द्वारा जारी किए गए Transact-SQL स्टेटमेंट के लॉकिंग और रो संस्करण व्यवहार को नियंत्रित करता है।" और "यह निर्दिष्ट करता है कि कथन उन पंक्तियों को पढ़ सकते हैं जिन्हें अन्य लेनदेन द्वारा संशोधित किया गया है लेकिन अभी तक प्रतिबद्ध नहीं हैं।" मैंने जो यह कथन लिखा है वह हर SQL कथन को प्रभावित करता है, यह एक लेनदेन के अंदर है या नहीं। मुझे लोगों को ऑनलाइन विरोधाभास करना पसंद नहीं है, लेकिन आप एक बड़े उत्पादन वातावरण में इस कथन के हमारे उपयोग के आधार पर स्पष्ट रूप से गलत हैं। चीजों को मत मानो, कोशिश करो!
फ्रैंक। जर्मेन

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

3
@DoctorJones - Microsoft SQL सर्वर के संबंध में, सभी प्रश्न स्वाभाविक रूप से लेनदेन हैं। एक स्पष्ट लेनदेन को निर्दिष्ट करना एक ही लेनदेन में 2 या अधिक बयानों को समूहीकृत करने का एक साधन है, ताकि उन्हें कार्य की एक परमाणु इकाई माना जा सके। SET TRANSACTION ISOLATION LEVEL...आदेश एक कनेक्शन स्तरीय संपत्ति को प्रभावित करता है और जब तक एक प्रश्न संकेत द्वारा ओवरराइड इसलिए, सभी एसक्यूएल उस समय के बाद (उस कनेक्शन के लिए) से दिए गए बयान को प्रभावित करता है। यह व्यवहार कम से कम SQL Server 2000 के आसपास रहा है, और पहले भी संभव है।
सोलोमन रटज़की 15

5
@DoctorJones - की जाँच करें: msdn.microsoft.com/en-us/library/ms173763.aspx । यहाँ एक परीक्षण है। SSMS में, एक क्वेरी (# 1) खोलें और चलाएँ CREATE TABLE ##Test(Col1 INT); BEGIN TRAN; SELECT * FROM ##Test WITH (TABLOCK, XLOCK);:। एक और क्वेरी (# 2) खोलें और चलाएँ SELECT * FROM ##Test;:। SELECT नहीं लौटेगा क्योंकि यह टैब # 1 में अभी भी खुले लेनदेन द्वारा अवरुद्ध किया जा रहा है जो एक विशेष लॉक का उपयोग कर रहा है। # 2 में चयन रद्द करें। SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDटैब # 2 में एक बार चलाएं । टैब # 2 में फिर से सिलेक्ट रन करें और यह वापस आ जाएगा। ROLLBACKटैब # 1 में चलना सुनिश्चित करें ।
सोलोमन रटज़की

21

हालाँकि मैं इस बात से बिल्कुल सहमत था कि Read Uncommitted लेन-देन अलगाव स्तर का उपयोग करना सबसे अच्छा विकल्प है, लेकिन कुछ समय आपने प्रबंधक या क्लाइंट के अनुरोध पर NOLOCK संकेत का उपयोग करने के लिए मजबूर किया और इसके विरुद्ध कोई कारण स्वीकार नहीं किया गया।

एंटिटी फ्रेमवर्क 6 के साथ आप स्वयं DbCommandInterceptor को इस तरह लागू कर सकते हैं:

public class NoLockInterceptor : DbCommandInterceptor
{
    private static readonly Regex _tableAliasRegex = 
        new Regex(@"(?<tableAlias>AS \[Extent\d+\](?! WITH \(NOLOCK\)))", 
            RegexOptions.Multiline | RegexOptions.IgnoreCase);

    [ThreadStatic]
    public static bool SuppressNoLock;

    public override void ScalarExecuting(DbCommand command, 
        DbCommandInterceptionContext<object> interceptionContext)
    {
        if (!SuppressNoLock)
        {
            command.CommandText = 
                _tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
        }
    }

    public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        if (!SuppressNoLock)
        {
            command.CommandText = 
                _tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
        }
    }
}

इस श्रेणी के साथ, आप इसे आवेदन शुरू होने पर लागू कर सकते हैं:

DbInterception.Add(new NoLockInterceptor());

और सशर्त रूप से NOLOCKवर्तमान थ्रेड के लिए प्रश्नों में संकेत जोड़ना बंद करें :

NoLockInterceptor.SuppressNoLock = true;

मुझे यह समाधान पसंद है, हालांकि मैंने regex को थोड़ा बदल दिया:
Russ

2
(? <tableAlias>] AS [एक्सटेंट \ d +] (? (NOLOCK) के साथ))) व्युत्पन्न टेबल में नोलॉक जोड़ने से रोकने के लिए जो एक त्रुटि का कारण बनता है। :)
रस

SuppressNoLock को थ्रेड स्तर पर सेट करना एक सुविधाजनक तरीका है, लेकिन बूलियन को अनसुना करना आसान है, आपको एक ऐसे फ़ंक्शन का उपयोग करना चाहिए जो IDisposable को लौटाता है, डिस्पोज़ विधि बस बूल को फिर से गलत पर सेट कर सकती है। इसके अलावा, थ्रेडस्टैटिक वास्तव में async / प्रतीक्षा के साथ संगत नहीं है: stackoverflow.com/questions/13010563/…
Jaap

या, अगर आप इसके बजाय ISOLATION LEVEL का उपयोग करेंगे: public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { if (!SuppressNoLock) command.CommandText = $"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;{Environment.NewLine}{command.CommandText}"; base.ReaderExecuting(command, interceptionContext); }
Adi

यह डेटाबेस कार्यों के लिए भी नोलॉक को जोड़ रहा है। कार्यों के लिए कैसे बचें?
इवान लुईस

9

पर बढ़ाना डॉक्टर जोन्स के स्वीकार किए जाते हैं जवाब और का उपयोग कर PostSharp ;

पहला " ReadUncommitedTransactionScopeAttribute "

[Serializable]
public class ReadUncommitedTransactionScopeAttribute : MethodInterceptionAspect
{
    public override void OnInvoke(MethodInterceptionArgs args)
    {
        //declare the transaction options
        var transactionOptions = new TransactionOptions();
        //set it to read uncommited
        transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
        //create the transaction scope, passing our options in
        using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
        {
            //declare our context
            using (var scope = new TransactionScope())
            {
                args.Proceed();
                scope.Complete();
            }
        }
    }
}

फिर जब भी आपको आवश्यकता हो,

    [ReadUncommitedTransactionScope()]
    public static SomeEntities[] GetSomeEntities()
    {
        using (var context = new MyEntityConnection())
        {
            //any reads we do here will also read uncomitted data
            //...
            //...

        }
    }

एक इंटरसेप्टर के साथ "NOLOCK" को जोड़ने में सक्षम होना भी अच्छा है, लेकिन Oracle जैसे अन्य डेटाबेस सिस्टम से कनेक्ट होने पर काम नहीं करेगा।


6

इसे प्राप्त करने के लिए मैं डेटाबेस पर एक दृश्य बनाता हूं और दृश्य की क्वेरी पर NOLOCK लागू करता हूं। मैं तो दृश्य को EF के भीतर एक तालिका के रूप में मानता हूं।


4

EF6 की शुरुआत के साथ, Microsoft BeginTransaction () विधि का उपयोग करने की सलाह देता है।

आप EF6 + और EF कोर में TransactionScope के बजाय BeginTransaction का उपयोग कर सकते हैं

using (var ctx = new ContractDbContext())
using (var transaction = ctx.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
    //any reads we do here will also read uncommitted data
}

2

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

NOLOCK क्वेरी संकेत एक SQL सर्वर विशिष्ट बात है और किसी भी अन्य समर्थित डेटाबेस पर काम नहीं करेगा (जब तक कि उन्होंने भी वही संकेत लागू नहीं किया है - जो मुझे दृढ़ता से संदेह है)।

न घुलनेवाली तलछट


यह उत्तर पुराना है - आप NOLOCK का उपयोग कर सकते हैं जैसा कि अन्य लोगों ने उल्लेख किया है, और आप "देशी" SQL का उपयोग कर Database.ExecuteSqlCommand()या निष्पादित कर सकते हैं DbSet<T>.SqlQuery()
डनक

1
@ डंक: डाउनवोट के लिए धन्यवाद - btw: आपको किसी भी तरह से उपयोग नहीं करना चाहिए (NOLOCK)- बुरी आदत को किक करने के लिए देखें - हर जगह NOLOCK डालते हुए - यह हर जगह इस का उपयोग करने के लिए अनुशंसित नहीं है - काफी विपरीत!
marc_s

0

एक विकल्प संग्रहित प्रक्रिया (रयान द्वारा प्रस्तावित दृश्य समाधान के समान) का उपयोग करना है और फिर EF से संग्रहीत कार्यविधि को निष्पादित करना है। इस तरह से संग्रहीत प्रक्रिया गंदा रीडिंग करती है जबकि ईएफ केवल परिणामों को पाइप करता है।

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