2013-02-27 6 views
5

मेरे पास ओरेकल डेटाबेस है जिसे मैं देवर्ट और एंटिटी फ्रेमवर्क का उपयोग करके एक्सेस करता हूं।डेटाबेस तालिका में समवर्ती पढ़ने और अद्यतन

IMPORTJOBS नामक एक तालिका STATUS के साथ एक तालिका है।

मेरे पास एक ही समय में कई प्रक्रियाएं चल रही हैं। वे प्रत्येक IMPORTJOBS में पहली पंक्ति पढ़ते हैं जिसमें 'REGISTERED' स्थिति है, इसे 'EXECUTING' स्थिति में रखें, और यदि इसे 'EXECUTED' स्थिति में डाल दिया गया है।

अब क्योंकि इन प्रक्रियाओं समानांतर में चल रहे हैं, मेरा मानना ​​है कि निम्न हो सकता है:

  • प्रक्रिया एक पंक्ति 10 जो स्थिति REGISTERED है पढ़ता है,
  • प्रक्रिया बी भी पंक्ति 10 जो अभी भी है स्थिति REGISTERED पढ़ता ,
  • प्रक्रिया EXECUTING स्थिति के लिए एक पंक्ति पंक्ति 10 अद्यतन।

प्रक्रिया बी पंक्ति 10 को पढ़ने में सक्षम नहीं होना चाहिए क्योंकि प्रक्रिया ए पहले ही इसे पढ़ चुकी है और इसकी स्थिति अपडेट करने जा रही है।

मुझे इसे कैसे हल करना चाहिए? एक लेनदेन में पढ़ और अद्यतन रखो? या मुझे कुछ संस्करण दृष्टिकोण या कुछ और उपयोग करना चाहिए?

धन्यवाद!

संपादित करें: स्वीकृत उत्तर के लिए धन्यवाद, मैंने इसे काम किया और इसे यहां दस्तावेज किया: http://ludwigstuyck.wordpress.com/2013/02/28/concurrent-reading-and-writing-in-an-oracle-database

उत्तर

2

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

ओरेकल 11 जी में, मेरा सुझाव है कि आप SKIP LOCKED सुविधा का उपयोग करें।

CREATE OR REPLACE TYPE tab_number IS TABLE OF NUMBER; 

CREATE OR REPLACE FUNCTION reserve_jobs RETURN tab_number IS 
    CURSOR c IS 
     SELECT id FROM IMPORTJOBS WHERE STATUS = 'REGISTERED' 
     FOR UPDATE SKIP LOCKED; 
    l_result tab_number := tab_number(); 
    l_id number; 
BEGIN 
    OPEN c; 
    FOR i IN 1..10 LOOP 
     FETCH c INTO l_id; 
     EXIT WHEN c%NOTFOUND; 
     l_result.extend; 
     l_result(l_result.size) := l_id; 
    END LOOP; 
    CLOSE c; 
    RETURN l_result; 
END; 

यह 10 पंक्तियाँ वापस आ जाएगी (यदि संभव हो तो) कि बंद नहीं कर रहे हैं: उदाहरण के लिए प्रत्येक प्रक्रिया इस तरह एक समारोह (यह मानते हुए id संख्या में हैं) कह सकते हैं। इन पंक्तियों को बंद कर दिया जाएगा और सत्र एक-दूसरे को अवरुद्ध नहीं करेंगे।

ओरेकल लगातार परिणाम लौटने के बाद 10g और इससे पहले, FOR UPDATE बुद्धिमानी से उपयोग करें और आपको उस समस्या का सामना नहीं करना चाहिए जिसका आप वर्णन करते हैं। मिसाल के तौर पर विचार करना निम्नलिखित SELECT:

SELECT * 
    FROM IMPORTJOBS 
WHERE STATUS = 'REGISTERED' 
    AND rownum <= 10 
FOR UPDATE; 

अगर सभी प्रक्रियाओं इस चयन के साथ उनकी पंक्तियों को आरक्षित क्या होगा? यह आपके परिदृश्य को कैसे प्रभावित करेगा:

  1. सत्र ए को 10 पंक्तियां मिलती हैं जिन्हें संसाधित नहीं किया जाता है।
  2. सत्र बी को वही 10 पंक्तियां मिलेंगी, अवरुद्ध है और सत्र ए
  3. सत्र एक चयनित पंक्तियों की स्थिति अपडेट करता है और इसके लेनदेन को करता है।
  4. ओरेकल अब (स्वचालित रूप से) सत्र बी के चयन को फिर से शुरू कर देगा क्योंकि डेटा संशोधित किया गया है और हमने FOR UPDATE निर्दिष्ट किया है (यह खंड ब्लॉक के अंतिम संस्करण को प्राप्त करने के लिए ओरेकल को मजबूर करता है)।
    इसका मतलब है कि सत्र बी को 10 नई पंक्तियां मिल जाएगी।

तो इस परिदृश्य में, आपके पास कोई स्थिरता समस्या नहीं है। साथ ही, यह मानते हुए कि एक पंक्ति का अनुरोध करने और इसकी स्थिति बदलने के लिए लेनदेन तेजी से है, समेकन प्रभाव हल्का होगा।

+0

धन्यवाद, मैं आयात सूची से "चयन * निष्पादित करने की कोशिश कर रहा हूं जहां स्टेटसकोडे = 'पंजीकृत' और ROWNUM <= 1 अपडेट की गई अद्यतन के लिए <= 1 है, लेकिन यह अभी भी विभिन्न प्रक्रियाओं से एक ही पंक्ति को वापस कर रहा है? –

+1

(1) सुनिश्चित करें कि आपने ऑटोकॉमिट बंद कर दिया है: आप लेनदेन के बिना एक पंक्ति को लॉक नहीं कर सकते हैं। (2) 'अपडेट स्कीप लॉकड' और 'राउनम' के लिए [जैसा कि आप उम्मीद करते हैं उतना काम नहीं करेगा] (http://stackoverflow.com/questions/5847228/oracle-select-for-update-behaviour) - ऐसा इसलिए है क्योंकि ** WHERE क्लॉज के बाद ** स्किप लॉकड का मूल्यांकन ** किया जाता है। बिना किसी राउनम के चयन का उपयोग करें, एक (या आवश्यकतानुसार अधिक) पंक्ति प्राप्त करें और कर्सर को बंद करें, यह स्किप लॉक का उपयोग करने का सबसे अच्छा तरीका है। –

+0

वास्तव में, मुझे एक लेनदेन में चयन और अद्यतन करना पड़ा, अब यह काम करता है। धन्यवाद!!! –

2

प्रत्येक प्रक्रिया SELECT ... FOR UPDATE जारी करके पंक्ति को लॉक करने के लिए जारी कर सकती है। इस परिदृश्य में, प्रक्रिया ए पंक्ति को पढ़ और लॉक कर देगा, प्रक्रिया बी पंक्ति को पढ़ने और प्रक्रिया को तब तक ब्लॉक करने का प्रयास करेगी जब तक कि ए लेन-देन (या वापस रोलिंग) करके लॉक जारी नहीं करता है। ओरेकल तब निर्धारित करेगा कि पंक्ति अभी भी बी के मानदंडों को पूरा करती है और, आपके उदाहरण में, पंक्ति को बी पर वापस नहीं लाएगी। यह काम करता है लेकिन इसका मतलब है कि आपकी बहु-थ्रेडेड प्रक्रिया अब आपके लेनदेन नियंत्रण के आधार पर प्रभावी रूप से सिंगल-थ्रेडेड हो सकती है काम करने की जरूरत है।

संभव तरीके scalability

  • एक उपभोक्ता पर अपेक्षाकृत आम दृष्टिकोण अलग धागे के लिए काम से बाहर हल करने के लिए इस एक भी समन्वयक धागा उस तालिका से डेटा पढ़ता है, पार्सल करने के लिए सुधार करने के लिए, और अद्यतन करता है तालिका उचित रूप से (यह जानकर कि नौकरी को दोबारा सौंपने के तरीके को जानना, अगर थ्रेड को सौंपा गया था)।
  • आप ओरेकल 11.1 या बाद में उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं अपने FOR UPDATE ताकि प्रत्येक सत्र पहली पंक्ति है कि उनके मानदंडों को पूरा करती है और बंद नहीं किया जाता है (खंड पिछले संस्करणों में ही अस्तित्व में है, लेकिन यह तो दर्ज नहीं किया गया था वापस हो जाता है पर SKIP LOCKED clause सही ढंग से काम नहीं कर सकता है)।
  • ImportJobs के लिए तालिका का उपयोग करने के बजाय, आप एकाधिक उपभोक्ताओं के साथ एक कतार का उपयोग कर सकते हैं। यह ओरेकल को प्रत्येक प्रक्रिया में संदेश वितरित करने की अनुमति देगा, बिना किसी अतिरिक्त लॉकिंग के निर्माण के लिए (ओरेकल कतार दृश्यों के पीछे यह सब कर रही हैं)।
1

versioning and optimistic concurrency का उपयोग करें।

IMPORTJOBS तालिका में आपके मॉडल में ConcurrencyMode = Fixed के रूप में चिह्नित एक टाइमस्टैम्प कॉलम होना चाहिए। अब जब ईएफ अपडेट करने का प्रयास करता है तो टाइमस्टैम्प कॉलम अपडेट स्टेटमेंट में शामिल होता है: WHERE timestamp = xxxxx

B के लिए, टाइमस्टैम्प औसत समय में बदल गया, इसलिए एक समेकन अपवाद उठाया गया है, जो इस मामले में, आप अद्यतन को छोड़कर संभालते हैं।

मैं एक SQL सर्वर पृष्ठभूमि से हूं और मुझे ओरेकल टाइमस्टैम्प (या पंक्तिवर्तन) के बराबर नहीं पता है, लेकिन विचार यह है कि यह एक ऐसा क्षेत्र है जो रिकॉर्ड के लिए अद्यतन होने पर स्वतः अपडेट होता है।

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