2009-08-19 5 views

उत्तर

8

यदि आप इसे अपने कई प्रश्नों में उपयोग करने जा रहे हैं, तो आप इसे कॉन्फ़िगरेशन प्रॉपर्टी connection.isolation के माध्यम से डिफ़ॉल्ट रूप से सेट कर सकते हैं।

<property name="connection.isolation">ReadUncommitted</property> 

documentation on this property देखें।

+0

यह मेरे लिए काम किया! ReadCommitted पढ़ने के लिए web.config प्रविष्टि को बदलना अस्वीकृत अपवाद हटा दिया गया है। मैं समझता हूं कि पढ़ना अब 'गंदे' हो सकता है लेकिन मुझे लगता है कि उपयोगकर्ता के सत्र/अनुभव को अवरुद्ध करने और मारने से बेहतर विकल्प है। अगर वे गंदे डेटा देखते हैं तो यह माना जाता है कि यह अभी तक दृश्य पर अपडेट नहीं हुआ है और यह अगला पृष्ठदृश्य होगा। अच्छा समाधान। हालांकि यह वास्तविक समस्या को संबोधित नहीं करता है, और पृष्ठों को अभी भी लोड करने में काफी समय लगता है - इसने डेडलॉक त्रुटियों को समाप्त कर दिया है। – dankeshawn

19

SetLockMode(LockMode.None) या connection.isolation ReadUncomitted आपके प्रश्नों में NOLOCK संलग्न नहीं करता है। आप आप निम्न कर सकते <sql-query> उपयोग कर रहे हैं

:

<sql-query name="PeopleByName"> 
    <return alias="person" 
        class="Person"/> 
    SELECT {person.*} 
    FROM People {person} WITH(nolock) 
    WHERE {person}.Name LIKE :name 
</sql-query> 

नोट WTIH(nolock)FROM खंड के साथ जोड़ दिया

Ayende correct answer on his blog में चला जाता है।

+2

लेकिन 'असामान्य पढ़ने के लिए कनेक्शन लेनदेन अलगाव स्तर को सेट करना एक क्वेरी में प्रत्येक तालिका में जोड़ने (नोलॉक) के बराबर है, है ना? – codeulike

+0

अंतर यह है कि मुझे लगता है कि NOLOCK एक विशिष्ट तालिका निर्दिष्ट करता है, जबकि अनदेखा पढ़ते हुए प्रत्येक तालिका निर्दिष्ट करता है। मैं कल्पना नहीं कर सकता कि यह एक मुद्दा अक्सर होगा ... लेकिन शायद। – PJUK

+0

@codeulike मैं तर्क के साथ बहस करूंगा, कृपया इसे http://technet.microsoft.com/en-us/library/ms187373.aspx देखें; चूंकि यह समान कार्यक्षमता में मदद कर सकता है लेकिन यह वही नहीं है और नोलॉक आपको डेटा पढ़ने में मदद करता है जिसे कभी-कभी गंदे पढ़ने के लिए कहा जाता है, लेकिन यह आपको लाखों पंक्तियों या अभिलेखों से निपटने के दौरान गति में सुधार करने में मदद करता है .. अन्यथा कोई क्यों चुनेगा nHibernate !! – MarmiK

15

मैं यह समझाऊंगा कि आप ऐसा कैसे करें ताकि आप एनओएलओकेके (या कोई अन्य प्रश्न संकेत) जोड़ सकें, जबकि अभी भी आईसीआरटीरिया या एचक्यूएल का उपयोग कर रहे हों, और मैपिंग या सत्र फैक्टरी कॉन्फ़िगरेशन में अपने प्रश्नों के ज्ञान को छूने के बिना।

मैंने इसे NHibernate 2.1 के लिए लिखा था। इसके साथ कई प्रमुख चेतावनी हैं, ज्यादातर एनएचबेर्नेट में बग के कारण जब "use_sql_comments" चालू होती है (नीचे देखें)। मुझे यकीन नहीं है कि क्या इन बग को एनएच 3 में तय किया गया है, लेकिन इसे आज़माएं। अद्यतन: बग को एनएच 3.3 के रूप में तय नहीं किया गया है। यहां वर्णित तकनीक और कामकाज अभी भी काम करते हैं।

सबसे पहले,, एक इंटरसेप्टर बनाने इस तरह:

[Serializable] 
public class QueryHintInterceptor : EmptyInterceptor 
{ 
    internal const string QUERY_HINT_NOLOCK_COMMENT = "queryhint-nolock: "; 

    /// <summary> 
    /// Gets a comment to add to a sql query to tell this interceptor to add 'OPTION (TABLE HINT(table_alias, INDEX = index_name))' to the query. 
    /// </summary> 
    internal static string GetQueryHintNoLock(string tableName) 
    { 
     return QUERY_HINT_NOLOCK_COMMENT + tableName; 
    } 

    public override SqlString OnPrepareStatement(SqlString sql) 
    { 
     if (sql.ToString().Contains(QUERY_HINT_NOLOCK_COMMENT)) 
     { 
      sql = ApplyQueryHintNoLock(sql, sql.ToString()); 
     } 

     return base.OnPrepareStatement(sql); 
    } 

    private static SqlString ApplyQueryHintNoLock(SqlString sql, string sqlString) 
    { 
     var indexOfTableName = sqlString.IndexOf(QUERY_HINT_NOLOCK_COMMENT) + QUERY_HINT_NOLOCK_COMMENT.Length; 

     if (indexOfTableName < 0) 
      throw new InvalidOperationException(
       "Query hint comment should contain name of table, like this: '/* queryhint-nolock: tableName */'"); 

     var indexOfTableNameEnd = sqlString.IndexOf(" ", indexOfTableName + 1); 

     if (indexOfTableNameEnd < 0) 
      throw new InvalidOperationException(
       "Query hint comment should contain name of table, like this: '/* queryhint-nlock: tableName */'"); 

     var tableName = sqlString.Substring(indexOfTableName, indexOfTableNameEnd - indexOfTableName).Trim(); 

     var regex = new Regex(@"{0}\s(\w+)".F(tableName)); 

     var aliasMatches = regex.Matches(sqlString, indexOfTableNameEnd); 

     if (aliasMatches.Count == 0) 
      throw new InvalidOperationException("Could not find aliases for table with name: " + tableName); 

     var q = 0; 
     foreach (Match aliasMatch in aliasMatches) 
     { 
      var alias = aliasMatch.Groups[1].Value; 
      var aliasIndex = aliasMatch.Groups[1].Index + q + alias.Length; 

      sql = sql.Insert(aliasIndex, " WITH (NOLOCK)"); 
      q += " WITH (NOLOCK)".Length; 
     } 
     return sql; 
    } 

    private static SqlString InsertOption(SqlString sql, string option) 
    { 
     // The original code used just "sql.Length". I found that the end of the sql string actually contains new lines and a semi colon. 
     // Might need to change in future versions of NHibernate. 
     var regex = new Regex(@"[^\;\s]", RegexOptions.RightToLeft); 
     var insertAt = regex.Match(sql.ToString()).Index + 1; 
     return sql.Insert(insertAt, option); 
    } 
} 

तो कहीं कुछ अच्छा विस्तार तरीकों बनाएँ:

public static class NHibernateQueryExtensions 
{ 
    public static IQuery QueryHintNoLock(this IQuery query, string tableName) 
    { 
     return query.SetComment(QueryHintInterceptor.GetQueryHintNoLock(tableName)); 
    } 

    public static ICriteria QueryHintNoLock(this ICriteria query, string tableName) 
    { 
     return query.SetComment(QueryHintInterceptor.GetQueryHintNoLock(tableName)); 
    } 
} 

इसके बाद, NHibernate बता अपने इंटरसेप्टर उपयोग करने के लिए:

config.SetInterceptor(new QueryHintInterceptor()); 

अंत में, उपयोग_sql_comments संपत्ति सक्षम करें आपके एनएचबीर्नेट कॉन्फ़िगरेशन में।

और आप कर चुके हैं! अब आप इस तरह nolock संकेत जोड़ सकते हैं: http://www.codewrecks.com/blog/index.php/2011/07/23/use-sql-server-query-hints-with-nhibernate-hql-and-icriteria/

NHibernate showstopping बग्स:

var criteria = Session.CreateCriteria<Foo>() 
    .QueryHintNoLock("tableFoo") 
    .List<Foo>(); 

मैं तकनीक यहाँ वर्णित चारों ओर इस काम के आधार

सबसे पहले, वहाँ है NHibernate है कि आप के साथ this bug ठीक करने की आवश्यकता होगी। (आप या तो NHibernate स्रोत सीधे मरम्मत, या by doing what I did और अपने खुद के बोली जो मरम्मत मुद्दा बनाकर इस बग को ठीक कर सकते हैं)।

दूसरे, वहाँ एक और बग जो तब होता है जब आप पहले पृष्ठ के बाद एक पृष्ठांकित क्वेरी करते हैं, किसी भी पृष्ठ पर लगता है, और आप के अनुमानों का उपयोग कर रहे हैं। NHBernate द्वारा उत्पन्न एसक्यूएल "ओवर" खंड के आसपास पूरी तरह से गलत है।इस स्तर पर मुझे नहीं पता कि इस बग को कैसे ठीक किया जाए लेकिन मैं इस पर काम कर रहा हूं। अपडेट: मैंने इस बग को here को ठीक करने का विवरण दिया है। अन्य बग की तरह, यह भी एनएचबेर्नेट स्रोत कोड की मरम्मत करके या अपनी खुद की बोलीभाषा वर्ग बनाकर तय किया जा सकता है।

+0

के समान काम करता है यह प्रक्रिया गतिशील रूप से एक एसक्यूएल का निर्माण करती है। ऐसा करने के लाभ कैशिंग के बारे में क्या? – Luciano

5

यह आपके प्रश्नों के लिए NOLOCK नहीं जोड़ता है जो मैं बता सकता हूं, लेकिन इसे समान कार्यक्षमता प्रदान करनी चाहिए - जो केवल लेनदेन के अंदर गंदे पढ़ने के लिए है।

Session.BeginTransaction(IsolationLevel.ReadUncommitted); 

मैं Sql प्रोफाइलर इस्तेमाल किया उपरोक्त आदेश क्या करेंगे देखने के लिए, लेकिन यह क्वेरी के बारे में कुछ भी बदल सकते हैं या उन्हें NOLOCK में नहीं जोड़ा था (nhibernate सबसे मेरी प्रश्नों के लिए sp_executesql का उपयोग करता है)। मैं वैसे भी इसके साथ भाग गया, और ऐसा लगता है कि सभी deadlocks चले गए हैं। हमारा सॉफ्टवेयर डेडलॉक्स के बिना 3 दिनों के लिए इस तरह से चल रहा है। इस बदलाव से पहले मैं आमतौर पर 15 मिनट के भीतर डेडलॉक्स को पुन: उत्पन्न कर सकता था। मुझे 100% यकीन नहीं है कि यह तय है लेकिन परीक्षण के लायक एक और सप्ताह के बाद मैं और जानूंगा।

यह दूसरों के लिए काम किया है और साथ ही: http://quomon.com/NHibernate-deadlock-problem-q43633.aspx

+0

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

0

आप इंटरसेप्टर का उपयोग करके इसे हल कर सकते हैं।

var session = SessionFactory.OpenSession(new NoLockInterceptor()); 

नोलॉकइंटरसेप्टर कक्षा के लिए कार्यान्वयन यहां दिया गया है। मूल रूप से NoLockInterceptor क्लास nHibernate द्वारा जेनरेट की गई चुनिंदा क्वेरी में प्रत्येक तालिका नाम के बाद "बिना (NOLOCK)" संकेत डालेगा।


public class NoLockInterceptor : EmptyInterceptor 
{ 
    public override SqlString OnPrepareStatement(SqlString sql) 
     { 
      //var log = new StringBuilder(); 
      //log.Append(sql.ToString()); 
      //log.AppendLine(); 

      // Modify the sql to add hints 
      if (sql.StartsWithCaseInsensitive("select")) 
      { 
       var parts = sql.ToString().Split().ToList(); 
       var fromItem = parts.FirstOrDefault(p => p.Trim().Equals("from", StringComparison.OrdinalIgnoreCase)); 
       int fromIndex = fromItem != null ? parts.IndexOf(fromItem) : -1; 
       var whereItem = parts.FirstOrDefault(p => p.Trim().Equals("where", StringComparison.OrdinalIgnoreCase)); 
       int whereIndex = whereItem != null ? parts.IndexOf(whereItem) : parts.Count; 

       if (fromIndex == -1) 
        return sql; 

       parts.Insert(parts.IndexOf(fromItem) + 3, "WITH (NOLOCK)"); 
       for (int i = fromIndex; i < whereIndex; i++) 
       { 
        if (parts[i - 1].Equals(",")) 
        { 
         parts.Insert(i + 3, "WITH (NOLOCK)"); 
         i += 3; 
        } 
        if (parts[i].Trim().Equals("on", StringComparison.OrdinalIgnoreCase)) 
        { 
         parts[i] = "WITH (NOLOCK) on"; 
        } 
       } 
       // MUST use SqlString.Parse() method instead of new SqlString() 
       sql = SqlString.Parse(string.Join(" ", parts)); 
      } 

      //log.Append(sql); 
      return sql; 
     } 
}