2009-04-22 8 views
14

एनएचबर्ननेट में, मैं एक उदाहरण पुनर्प्राप्त करना चाहता हूं, और रिकॉर्ड पर एक विशेष लॉक डालता हूं जो डेटाबेस पर पुनर्प्राप्त इकाई का प्रतिनिधित्व करता है।NHibernate: अनन्य लॉकिंग

With.Transaction (session, IsolationLevel.Serializable, delegate 
{ 
    ICriteria crit = session.CreateCriteria (typeof (TarificationProfile)); 

    crit.SetLockMode (LockMode.Upgrade); 

    crit.Add (Expression.Eq ("Id", tarificationProfileId)); 

    TarificationProfile profile = crit.UniqueResult<TarificationProfile>(); 

    nextNumber = profile.AttestCounter; 

    profile.AttestCounter++; 

    session.SaveOrUpdate (profile); 
}); 

आप देख सकते हैं, मैं इस मानदंड 'अपग्रेड करें' के लिए LockMode सेट:

अभी, मैं इस कोड है।

हालांकि, मैं एक असली अनन्य लॉक का उपयोग करने के लिए सक्षम होना चाहते हैं: यह जो updlock और rowlock ताला लगा संकेत का उपयोग करता है एसक्यूएल सर्वर के लिए एक एसक्यूएल बयान जारी करता है। यही है, जब तक कि मैंने लॉक जारी नहीं किया है, तब तक अन्य लोग इस रिकॉर्ड को पढ़ सकते हैं। दूसरे शब्दों में, मैं की बजाय xlock लॉकिंग संकेत का उपयोग करने में सक्षम होना चाहता हूं।

मैं नहीं जानता कि कैसे (या यहां तक ​​कि अगर) मुझे लगता है कि प्राप्त कर सकते हैं .... शायद किसी ने मुझसे इस :)

तो यह वास्तव में आवश्यक है, मैं SQLQuery कार्यक्षमता का उपयोग कर सकते हैं के बारे में कुछ संकेत दे सकते हैं NHibernate का, और अपना स्वयं का SQL क्वेरी लिखें, लेकिन, मैं जितना संभव हो उससे बचना चाहता हूं।

+0

आप एक विशेष ताला प्राप्त करने के लिए क्यों चाहते हो? शायद अन्य समाधान हैं। –

+0

क्यों? क्योंकि यह जरूरी है ... मेरी इकाई में एक काउंटर शामिल है जिसका उपयोग किया जाना चाहिए, और मुझे पूरी तरह से यह सुनिश्चित करना होगा कि यह काउंटर सही ढंग से उपयोग किया जाता है ... –

+0

क्या आपको पढ़ते समय लॉक नहीं करना चाहिए? –

उत्तर

7

एक एचक्यूएल डीएमएल क्वेरी लॉक की आवश्यकता के बिना आपके अपडेट को पूरा करेगी।

यह NHibernate 2.1 में उपलब्ध है, लेकिन अभी तक संदर्भ दस्तावेज़ में नहीं है। जावा hibernate documentation एनएचबेर्नेट कार्यान्वयन के बहुत करीब है।

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

With.Transaction (session, IsolationLevel.Serializable, delegate 
{ 
    session.CreateQuery("update TarificationProfile t set t.AttestCounter = 1 + t.AttestCounter where t.id=:id") 
     .SetInt32("id", tarificationProfileId) 
     .ExecuteUpdate(); 

    nextNumber = session.CreateQuery("select AttestCounter from TarificationProfile where Id=:id") 
     .SetInt32("id", id) 
     .UniqueResult<int>(); 
} 

अपनी मेज और स्तंभ नाम के आधार पर, उत्पन्न एसक्यूएल होगा:

update TarificationProfile 
set AttestCounter = 1 + AttestCounter 
where Id = 1 /* @p0 */ 

select tarificati0_.AttestCounter as col_0_0_ 
from TarificationProfile tarificati0_ 
where tarificati0_.Id = 1 /* @p0 */ 
+0

को शामिल करने के लिए अपना उत्तर अपडेट किया है, लेकिन मुझे अगले एटस्ट काउंटर को भी जानना होगा। इसलिए, मुझे नया मान पुनर्प्राप्त करने की आवश्यकता है ... –

+0

@Frederik ने नया मान –

+0

लाने के लिए उदाहरण अपडेट किया है क्या आप वाकई सही AttestCounter प्राप्त करेंगे? मेरा मतलब है, क्या यहां होने के लिए कोई रेसिंग स्थितियां नहीं हैं, या क्या इसे सीरियलज़ेबल अलगाव स्तर से हल किया गया है? –

0

यदि आप यह सुनिश्चित करना चाहते हैं कि डेटाबेस से पढ़े गए मान लेनदेन के दौरान नहीं बदलते हैं तो आप अलगाव स्तर "दोहराने योग्य पढ़ने" का उपयोग कर सकते हैं। लेकिन आपको यह सभी महत्वपूर्ण लेनदेन में करना है। या आप इसे अपग्रेड लॉक के साथ महत्वपूर्ण रीडिंग लेनदेन में लॉक करते हैं।

+0

thx है, क्या आप उस पर थोड़ा और विस्तार कर सकते हैं? मैं एक लेनदेन का उपयोग करता हूं, जहां मैंने इकाई को पढ़ा है (अभी एक अपडेटलॉक के साथ), और मैं उसी लेनदेन में अद्यतन इकाई को सहेजता हूं। –

+0

तो इस लेनदेन के दौरान इकाई बदल नहीं सकती है। अन्य लेनदेन मूल्य पढ़ सकते हैं, और वे अपने लेनदेन के दौरान आपके परिवर्तन देख सकते हैं। अगर उन्हें यह पसंद नहीं है, तो उन्हें अपना खुद का ताला बनाना होगा। या "दोहराने योग्य पढ़ने" का उपयोग करें। –

1

यदि आप पढ़ते हैं तो सीरियलज़ेबल के अलगाव लेवेल के साथ किया जाता है और सभी लिखने को सीरियलज़ेबल के अलगाव लेवेल के साथ भी किया जाता है, मुझे नहीं लगता कि आपको डेटाबेस की किसी भी लॉकिंग को अपने आप को क्यों करना है।

तो serialize डेटा को सुरक्षित रखता है, अब हम अभी भी संभव मृत ताले की समस्या ....

है गतिरोध आम, बस डाल नहीं कर रहे हैं [लेन-देन शुरू करते हैं, पढ़ते हैं, अद्यतन, बचाने] जब आप डेडलॉक प्राप्त करते हैं तो एक पुनः प्रयास लूप में पर्याप्त हो सकता है।

अन्यथा सीधे उत्पन्न होने वाले एक सरल "अद्यतन के लिए चयन करें" कथन (उदा। निबर्ननेट के साथ नहीं) का उपयोग दूसरे लेनदेन को बदलने से पहले पंक्ति को पढ़ने के लिए किया जा सकता है।

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

+1

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

+0

@ सैम, धन्यवाद, मैंने डेडलॉक्स –

3

मुझे संदेह है कि यह एनएचबेर्नेट से किया जा सकता है। निजी तौर पर, मैं जो भी करने की कोशिश कर रहा हूं उसे करने के लिए एक संग्रहित प्रक्रिया का उपयोग करता हूं।

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

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