ओआरए -01000, अधिकतम-खुले-कर्सर त्रुटि, ओरेकल डेटाबेस विकास में एक अत्यंत सामान्य त्रुटि है। जावा के संदर्भ में, यह तब होता है जब अनुप्रयोग डेटाबेस परिणाम पर कॉन्फ़िगर किए गए कर्सर की तुलना में अधिक परिणाम खोलने का प्रयास करता है।
सामान्य कारण हैं:
कॉन्फ़िगरेशन गलती
- आपके पास डीबी पर कर्सर की तुलना में डेटाबेस को क्वेरी करते हुए आपके आवेदन में अधिक धागे हैं। एक मामला यह है कि आपके पास डेटाबेस पर कर्सर की संख्या से बड़ा एक कनेक्शन और थ्रेड पूल है।
- आपके पास एक ही DB उदाहरण से जुड़े कई डेवलपर्स या एप्लिकेशन हैं (जिसमें संभवतः कई स्कीमा शामिल होंगे) और साथ में आप बहुत सारे कनेक्शन का उपयोग कर रहे हैं।
उपाय:
कर्सर लीक
- अनुप्रयोग ResultSets (JDBC में) या कर्सर को बंद नहीं कर रहे हैं (डेटाबेस में संग्रहीत कार्यविधियों में)
- समाधान : कर्सर लीक कीड़े हैं; DB पर अभिशापों की संख्या बढ़ने से बस अपरिहार्य विफलता होती है। लीक को स्थिर कोड विश्लेषण , जेडीबीसी या एप्लिकेशन-स्तर लॉगिंग और डेटाबेस मॉनिटरिंग का उपयोग करके पाया जा सकता है ।
पृष्ठभूमि
इस खंड में कर्सर के पीछे कुछ सिद्धांत का वर्णन है और JDBC का उपयोग कैसे किया जाना चाहिए। यदि आपको पृष्ठभूमि जानने की आवश्यकता नहीं है, तो आप इसे छोड़ सकते हैं और सीधे 'एलिमिनेटिंग लीक्स' पर जा सकते हैं।
एक कर्सर क्या है?
एक कर्सर डेटाबेस पर एक संसाधन है जो एक क्वेरी की स्थिति रखता है, विशेष रूप से उस स्थिति में जहां एक पाठक ResultSet में है। प्रत्येक सेलेक्ट स्टेटमेंट में एक कर्सर होता है, और PL / SQL स्टोर की गई प्रक्रिया को खोल सकते हैं और जितने की आवश्यकता होती है उतने कर्सर का उपयोग कर सकते हैं। आप Orafaq पर कर्सर के बारे में अधिक जानकारी प्राप्त कर सकते हैं ।
एक डेटाबेस उदाहरण आम तौर पर कई सत्रों के साथ कई अलग- अलग स्कीमा , कई अलग-अलग उपयोगकर्ता प्रदान करता है । ऐसा करने के लिए, इसमें सभी स्कीमा, उपयोगकर्ताओं और सत्रों के लिए निश्चित संख्या में कर्सर उपलब्ध हैं। जब सभी कर्सर खुले होते हैं (उपयोग में) और अनुरोध आता है जिसमें एक नए कर्सर की आवश्यकता होती है, तो ORA-010000 त्रुटि के साथ अनुरोध विफल हो जाता है।
शाप देने वालों की संख्या का पता लगाना और लगाना
स्थापना पर डीबीए द्वारा संख्या को सामान्य रूप से कॉन्फ़िगर किया गया है। वर्तमान में उपयोग किए जाने वाले कर्सर की संख्या, अधिकतम संख्या और कॉन्फ़िगरेशन को Oracle SQL डेवलपर में व्यवस्थापक कार्यों में एक्सेस किया जा सकता है । SQL से इसे इसके साथ सेट किया जा सकता है:
ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;
JVM में JDBC का संबंध DB पर श्रोताओं से है
नीचे दिए गए JDBC ऑब्जेक्ट्स को निम्नलिखित डेटाबेस अवधारणाओं के साथ कसकर जोड़ा गया है:
- JDBC कनेक्शन एक डेटाबेस सत्र का क्लाइंट प्रतिनिधित्व है और डेटाबेस लेनदेन प्रदान करता है । कनेक्शन में किसी भी समय केवल एक ही लेन-देन खुला हो सकता है (लेकिन लेनदेन को नस्ट किया जा सकता है)
- एक JDBC ResultSet एक भी द्वारा समर्थित है कर्सर डेटाबेस पर। जब ResultSet पर क्लोज़ () कॉल किया जाता है, तो कर्सर रिलीज़ होता है।
- JDBC CallableStatement डेटाबेस पर संग्रहीत कार्यविधि को आमंत्रित करता है , जिसे अक्सर PL / SQL में लिखा जाता है। संग्रहीत प्रक्रिया शून्य या अधिक कर्सर बना सकती है, और एक JDBC परिणाम के रूप में एक कर्सर वापस कर सकती है।
JDBC थ्रेड सुरक्षित है: थ्रेड के बीच विभिन्न JDBC ऑब्जेक्ट्स को पास करना काफी ठीक है।
उदाहरण के लिए, आप एक थ्रेड में कनेक्शन बना सकते हैं; एक अन्य थ्रेड इस कनेक्शन का उपयोग एक रेडीस्टेमेंट बनाने के लिए कर सकता है और एक तीसरा धागा परिणाम सेट को संसाधित कर सकता है। एकल प्रमुख प्रतिबंध यह है कि आप किसी भी समय किसी भी तैयारी पर एक से अधिक ResultSet नहीं खोल सकते हैं। देखें कनेक्शन के प्रति क्या Oracle DB समर्थन एकाधिक (समानांतर) के संचालन?
ध्यान दें कि किसी कनेक्शन पर एक डेटाबेस कमिट होता है, और इसलिए उस कनेक्शन पर सभी DML (INSERT, UPDATE और DELETE) एक साथ काम करेंगे। इसलिए, यदि आप एक ही समय में कई लेनदेन का समर्थन करना चाहते हैं, तो आपके पास प्रत्येक समवर्ती लेनदेन के लिए कम से कम एक कनेक्शन होना चाहिए।
JDBC ऑब्जेक्ट्स को बंद करना
एक परिणाम निष्पादित करने का एक विशिष्ट उदाहरण है:
Statement stmt = conn.createStatement();
try {
ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
try {
while ( rs.next() ) {
System.out.println( "Name: " + rs.getString("FULL_NAME") );
}
} finally {
try { rs.close(); } catch (Exception ignore) { }
}
} finally {
try { stmt.close(); } catch (Exception ignore) { }
}
ध्यान दें कि अंत में क्लोज़ द्वारा उठाए गए किसी भी अपवाद को कैसे अनदेखा किया जाता है ():
- यदि आप केवल {} कैच {} के बिना रिजल्टसेट को बंद करते हैं, तो यह विफल हो सकता है और स्टेटमेंट को बंद होने से रोक सकता है
- हम कॉलर को प्रचारित करने की कोशिश के शरीर में उठाए गए किसी भी अपवाद को अनुमति देना चाहते हैं। यदि आपके पास लूप ओवर है, उदाहरण के लिए, स्टेटमेंट बनाना और निष्पादित करना, तो लूप के भीतर प्रत्येक स्टेटमेंट को बंद करना याद रखें।
जावा 7 में, ओरेकल ने ऑटोक्लोसेबल इंटरफ़ेस पेश किया है जो जावा 6 बॉयलरप्लेट के अधिकांश को कुछ अच्छे सिंथैटिक चीनी के साथ बदल देता है।
होल्डिंग JDBC ऑब्जेक्ट्स
JDBC वस्तुओं को सुरक्षित रूप से स्थानीय चर, वस्तु उदाहरण और वर्ग के सदस्यों में रखा जा सकता है। यह आम तौर पर बेहतर अभ्यास है:
- JDBC ऑब्जेक्ट्स को रखने के लिए ऑब्जेक्ट उदाहरण या वर्ग के सदस्यों का उपयोग करें जो कि एक लंबी अवधि में कई बार पुन: उपयोग किए जाते हैं, जैसे कि कनेक्शंस और रेडीमेड्स
- रिजल्टसेट के लिए स्थानीय चरों का उपयोग करें क्योंकि ये प्राप्त किए जाते हैं, लूप किए जाते हैं और फिर एक फ़ंक्शन के दायरे में आम तौर पर बंद हो जाते हैं।
हालाँकि, एक अपवाद है: यदि आप EJB, या एक सर्वलेट / JSP कंटेनर का उपयोग कर रहे हैं, तो आपको एक सख्त थ्रेडिंग मॉडल का पालन करना होगा:
- केवल एप्लिकेशन सर्वर थ्रेड बनाता है (जिसके साथ यह आने वाले अनुरोधों को संभालता है)
- केवल एप्लिकेशन सर्वर कनेक्शन बनाता है (जो आप कनेक्शन पूल से प्राप्त करते हैं)
- कॉल के बीच मान (स्थिति) को सहेजते समय, आपको बहुत सावधान रहना होगा। अपने स्वयं के कैश या स्थिर सदस्यों में मूल्यों को कभी भी संग्रहीत न करें - यह क्लस्टर और अन्य अजीब स्थितियों में सुरक्षित नहीं है, और एप्लिकेशन सर्वर आपके डेटा के लिए भयानक काम कर सकता है। इसके बजाय स्टेटफुल बीन्स या डेटाबेस का उपयोग करें।
- विशेष रूप से, कभी नहीं पकड़ JDBC वस्तुओं (कनेक्शन, resultsets, PreparedStatements, आदि) विभिन्न दूरस्थ आमंत्रण से अधिक - अनुप्रयोग सर्वर इस का प्रबंधन करते हैं। एप्लिकेशन सर्वर न केवल एक कनेक्शन पूल प्रदान करता है, यह आपके रेडीस्टेमेंट्स को भी कैश करता है।
लीक को खत्म करना
JDBC लीक का पता लगाने और उसे खत्म करने में कई प्रक्रियाएं और उपकरण उपलब्ध हैं:
विकास के दौरान - कीड़े को जल्दी पकड़ना अब तक का सबसे अच्छा तरीका है:
विकास अभ्यास: अच्छे विकास अभ्यासों को आपके सॉफ़्टवेयर में बग्स की संख्या को कम करना चाहिए, इससे पहले कि वह डेवलपर के डेस्क को छोड़ दे। विशिष्ट प्रथाओं में शामिल हैं:
- जोड़ी प्रोग्रामिंग , पर्याप्त अनुभव के बिना उन लोगों को शिक्षित करने के लिए
- कोड समीक्षाएँ क्योंकि कई आँखें एक से बेहतर हैं
- इकाई परीक्षण जिसका अर्थ है कि आप किसी भी परीक्षण उपकरण से अपने सभी कोड आधार का उपयोग कर सकते हैं, जो प्रजनन को तुच्छ बनाता है
- अपने स्वयं के निर्माण के बजाय कनेक्शन पूलिंग के लिए मौजूदा पुस्तकालयों का उपयोग करें
स्टैटिक कोड विश्लेषण: एक स्थिर कोड विश्लेषण करने के लिए उत्कृष्ट फाइंडबग्स जैसे टूल का उपयोग करें । यह उन कई स्थानों को उठाता है जहाँ पास () को सही ढंग से संभाला नहीं गया है। फाइंडबग्स में एक्लिप्स के लिए एक प्लगइन है, लेकिन यह वन-ऑफ़ के लिए स्टैंडअलोन भी चलाता है, जेनकिंस सीआई और अन्य बिल्ड टूल में एकीकरण है
चलने के समय पर:
धारणीयता और प्रतिबद्धता
- यदि ResultSet धारण क्षमता ResultSet.CLOSE_CURSORS_OVER_COMMIT है, तो ResultSet को बंद कर दिया जाता है जब Connection.commit () विधि कहा जाता है। यह Connection.setHoldability () का उपयोग करके या ओवरलोड किए गए Connection.createStatement () विधि का उपयोग करके सेट किया जा सकता है।
रनटाइम पर लॉगिंग।
- अपने कोड में अच्छे लॉग स्टेटमेंट डालें। ये स्पष्ट और समझने योग्य होना चाहिए ताकि ग्राहक, सहयोगी स्टाफ और टीम के साथी प्रशिक्षण के बिना समझ सकें। उन्हें संक्षिप्त होना चाहिए और कुंजी चर और विशेषताओं के राज्य / आंतरिक मूल्यों को प्रिंट करना शामिल करना चाहिए ताकि आप प्रसंस्करण तर्क का पता लगा सकें। अच्छा लॉगिंग डिबगिंग अनुप्रयोगों के लिए मौलिक है, विशेष रूप से उन जिन्हें तैनात किया गया है।
आप अपने प्रोजेक्ट के लिए एक डीबगिंग JDBC ड्राइवर जोड़ सकते हैं (डिबगिंग के लिए - वास्तव में इसे लागू न करें)। एक उदाहरण (मैंने इसका इस्तेमाल नहीं किया है) log4jdbc है । फिर आपको इस फ़ाइल पर कुछ सरल विश्लेषण करने की आवश्यकता है, जो यह देखता है कि एक समान पास नहीं है। यदि संभावित समस्या है, तो खुले और बंद को गिनना चाहिए
- डेटाबेस की निगरानी करना। SQL डेवलपर 'मॉनिटर SQL' फ़ंक्शन या क्वेस्ट के TOAD जैसे टूल का उपयोग करके अपने रनिंग एप्लिकेशन की निगरानी करें । इस लेख में निगरानी का वर्णन किया गया है । निगरानी के दौरान, आप खुले कर्सर (जैसे तालिका v $ sesstat से) को क्वेरी करते हैं और उनके SQL की समीक्षा करते हैं। यदि कर्सर की संख्या बढ़ रही है, और (सबसे महत्वपूर्ण बात) एक समान एसक्यूएल स्टेटमेंट पर हावी हो रही है, तो आप जानते हैं कि आपके पास उस एसक्यूएल के साथ एक रिसाव है। अपना कोड खोजें और समीक्षा करें।
अन्य विचार
क्या आप समापन कनेक्शन को संभालने के लिए WeakReferences का उपयोग कर सकते हैं?
कमजोर और नरम संदर्भ आपको एक वस्तु को संदर्भित करने की अनुमति देने के तरीके हैं जो किसी भी समय जेवीएम को कचरा इकट्ठा करने की अनुमति देता है, वह फिट बैठता है (यह मानते हुए कि उस वस्तु के लिए कोई मजबूत संदर्भ श्रृंखला नहीं है)।
यदि आप कंस्ट्रक्टर में एक रेफ़रक्यूवे को सॉफ्ट या कमजोर रेफ़रेंस में पास करते हैं, तो ऑब्जेक्ट GCFed होने पर ऑब्जेक्ट रेफ़क्यूक्यू में रखा जाता है जब यह होता है (यदि यह बिल्कुल होता है)। इस दृष्टिकोण के साथ, आप ऑब्जेक्ट के अंतिमकरण के साथ बातचीत कर सकते हैं और आप उस पल में ऑब्जेक्ट को बंद या अंतिम कर सकते हैं।
प्रेत संदर्भ थोड़ा अजीब हैं; उनका उद्देश्य केवल अंतिम रूप को नियंत्रित करना है, लेकिन आप कभी भी मूल वस्तु का संदर्भ प्राप्त नहीं कर सकते हैं, इसलिए इस पर करीबी () विधि को कॉल करना मुश्किल होगा।
हालांकि, जब जीसी चलाया जाता है, तो इसे नियंत्रित करने का प्रयास करना शायद ही कभी एक अच्छा विचार है (कमजोर, नरम और फैंटमरेफरेंस आपको इस तथ्य के बाद पता चलता है कि ऑब्जेक्ट जीसी के लिए संलग्न है)। वास्तव में, अगर JVM में मेमोरी की मात्रा बड़ी है (उदाहरण के लिए -Xmx2000m) तो आप कभी भी ऑब्जेक्ट को GC नहीं कर सकते हैं , और आप ORA-01000 का अनुभव करेंगे। यदि JVM मेमोरी आपके प्रोग्राम की आवश्यकताओं के सापेक्ष छोटी है, तो आप पा सकते हैं कि ResultSet और ReadyedStatement ऑब्जेक्ट्स निर्माण के तुरंत बाद GCed हैं (इससे पहले कि आप उनसे पढ़ सकें), जो संभवतः आपके प्रोग्राम को विफल कर देगा।
TL; DR: कमजोर संदर्भ तंत्र स्टेटमेंट और रिजल्ट ऑब्जेक्ट्स को प्रबंधित और बंद करने का एक अच्छा तरीका नहीं है।
for (String language : additionalLangs) {