2008-09-19 26 views
49

मैं कर रहा हूँ कोड की समीक्षा हमारे पालतू परियोजनाओं में से एक के (ज्यादातर FindBugs जैसे उपकरणों का प्रयोग करके) और FindBugs गलत (स्यूडोकोड) के रूप में निम्न कोड में चिह्नित:परिणाम बंद होने पर परिणाम बंद नहीं है?

Connection conn = dataSource.getConnection(); 

try{ 
    PreparedStatement stmt = conn.prepareStatement(); 
    //initialize the statement 
    stmt.execute(); 
    ResultSet rs = stmt.getResultSet(); 
    //get data 
}finally{ 
    conn.close(); 
} 

त्रुटि थी कि इस कोड संसाधन नहीं जारी हो सकता है । मैं पता लगा कि ResultSet और वक्तव्य बंद नहीं किया गया, तो मैं अंत में में उन्हें बंद कर दिया:

finally{ 
    try{ 
     rs.close() 
    }catch(SqlException se){ 
     //log it 
    } 
    try{ 
     stmt.close(); 
    }catch(SqlException se){ 
     //log it 
    } 
    conn.close(); 
} 

लेकिन मैं कई परियोजनाओं में ऊपर पैटर्न (काफी कुछ कंपनियों से) का सामना करना पड़ा, और कोई भी resultsets बंद करने या था बयान।

क्या कनेक्शन के बंद होने पर परिणामस्वरूप बंद होने वाले परिणाम और विवरणों के साथ आपको परेशानी हो रही थी?

मुझे केवल this मिला और यह कनेक्शन को बंद करते समय ओरेकल को परिणाम परिणाम बंद करने में समस्याएं होती है (हम ओरेकल डीबी का उपयोग करते हैं, इसलिए मेरे सुधार)। java.sql.api Connection.close() javadoc में कुछ भी नहीं कहता है।

+0

मैं अत्यधिक अपाचे कॉमन्स-dbutils उपयोग करने की अनुशंसा (http://commons.apache.org/dbutils/) यह एक हल्के JDBC पुस्तकालय है कि वास्तव में बॉयलरप्लेट JDBC कोड का एक बहुत कुछ को साफ है। –

+2

यह उन त्रुटियों की तरह है जब वे प्रासंगिक वस्तुओं को बंद नहीं करते हैं - "ओआरए -01000: अधिकतम खुले कर्सर पार हो गए" - http: // stackoverflow।कॉम/प्रश्न/121925 9 2/जावा-एसक्यूएल-स्क्लेक्सप्शन-ओरा -01000-अधिकतम-खुले कर्सर- –

+0

डेटाबेस कर्सर से अधिक - http://stackoverflow.com/questions/3861558/what-are-the-benefits-of-using -डेटाबेस-कर्सर एक कर्सर एक ऐसा टूल है जो आपको सेट में रिकॉर्ड्स को फिर से चलाने की अनुमति देता है। इसमें आदेश और वर्तमान रिकॉर्ड की अवधारणाएं हैं। –

उत्तर

51

केवल कनेक्शन को बंद करने के साथ एक समस्या और परिणाम सेट नहीं, यह है कि यदि आपका कनेक्शन प्रबंधन कोड कनेक्शन पूलिंग का उपयोग कर रहा है, तो connection.close() कनेक्शन को वापस पूल में रखेगा। इसके अतिरिक्त, कुछ डेटाबेस में सर्वर पर एक कर्सर संसाधन होता है जिसे स्पष्ट रूप से बंद नहीं किया जाता है जब तक कि यह स्पष्ट रूप से बंद न हो जाए।

+14

कनेक्शन # क्लोज़ विधि के लिए javadocs कहता है कि "इस कनेक्शन ऑब्जेक्ट के डेटाबेस और जेडीबीसी संसाधनों को तुरंत जारी करता है"। मुझे लगता है कि समस्या यह है कि कुछ बुरे कार्यान्वयन सही काम नहीं करते हैं। जब पूल संबंधित संसाधनों को बंद नहीं करते हैं, तो क्या वे गलत काम कर रहे हैं? – marcospereira

+2

अधिकांश प्रमुख विक्रेता के जेडीबीसी ड्राइवर spec के अनुरूप हैं। हालांकि, अधिकांश (यदि नहीं सभी) एप्लिकेशन सर्वर कनेक्शन के पूल को बनाए रखते हैं। वे देशी कनेक्शन को लपेटते हैं और करीबी() जैसे तरीकों को पुन: कार्यान्वित करते हैं ताकि कनेक्शन 'पूल' हो सकें। इसका अर्थ यह है कि यदि आप इन परिवेशों में काम करते हैं, तो आपको अपने विवरण और संसाधनों जैसे संसाधनों को बंद करना होगा। –

+4

@ रयान फर्नांडीस: ठीक है, कुछ पूल सिर्फ आपको एक कनेक्शन देते हैं। प्रॉक्सी ऑब्जेक्ट जो उस पर सभी खुले बयान बचाता है। जब पूल में वापस आ जाता है, तो यह सभी खुले बयान बंद कर देता है। –

27

मुझे ओरेकल में अनजान परिणामसेट्स के साथ समस्याएं थीं, भले ही कनेक्शन बंद था। मुझे मिली त्रुटि

"ORA-01000: maximum open cursors exceeded" 

तो: हमेशा अपने परिणामसेट को बंद करें!

+1

+1 - बंद संसाधनों को बंद करने के परिणामों का जिक्र करने के लिए। –

8

ओरेकल आपको इस मामले में खुले कर्सर के बारे में त्रुटियां देगा।

के अनुसार

: http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

यह एक बयान पुन: उपयोग किसी भी खुले resultsets बंद हो जाएगा, और एक बयान को बंद करने के लिए किसी भी resultsets बंद हो जाएगा की तरह दिखता है, लेकिन मैं एक कनेक्शन बंद करने के बारे में कुछ भी नहीं दिख रहा है संसाधनों के किसी भी बंद हो जाएगा इसने बनाया।

उन सभी विवरणों को जेडीबीसी चालक प्रदाता को छोड़ दिया गया है।

यह सब कुछ स्पष्ट रूप से बंद करने के लिए हमेशा सुरक्षित है। हमने एक उपयोग वर्ग लिखा है जो कोशिश {xxx} पकड़ने (थ्रोबल {} के साथ सबकुछ लपेटता है ताकि आप अपवादों के बारे में चिंता किए बिना Utils.close (rs) और Utils.close (stmt) इत्यादि को कॉल कर सकें।

+0

_ लेकिन मुझे कनेक्शन बंद करने के बारे में कुछ भी दिखाई नहीं देता है, जो इसे बनाए गए किसी भी संसाधन को बंद कर देगा ._ http://docs.oracle.com/javase/6/docs/api/java/sql/Connection.html#close() _ इस कनेक्शन ऑब्जेक्ट के डेटाबेस ** और जेडीबीसी संसाधन ** तुरंत_ जारी करता है लेकिन हाँ, सब कुछ बंद करने के लिए हमेशा बेहतर होता है। – user454322

4

मैंने निश्चित रूप से अनजान परिणामसेट्स के साथ समस्याओं को देखा है, और यह हर समय उन्हें बंद करने के लिए क्या नुकसान पहुंचा सकता है, है ना? ऐसा करने के लिए याद रखने की आवश्यकता की अविश्वसनीयता है जो ढांचे को स्थानांतरित करने के लिए सबसे अच्छे कारणों में से एक है आपके लिए ये विवरण। यह आपके विकास के माहौल में संभव नहीं हो सकता है, लेकिन मुझे जेपीए लेनदेन का प्रबंधन करने के लिए वसंत का उपयोग करके बहुत अच्छा भाग्य मिला है। कनेक्शन खोलने, बयान, परिणाम सेट, और जटिल जटिल प्रयास/पकड़/आखिरकार ब्लॉक (आखिरकार ब्लॉक में को कोशिश करें/पकड़ें!) उन्हें फिर से बंद करने के लिए बस गायब हो जाता है, जिससे आप actuall पर जाते हैं y कुछ काम किया है। मैं अत्यधिक इस तरह के समाधान के लिए माइग्रेट करने की सिफारिश करता हूं।

+1

इस ऐप में यह एक बिंदु है। हम ईजेबी का उपयोग करते हैं, और यह हिस्सा प्लगइन की तरह था - हमारा क्लाइंट सीवर पर डेटास्रोत तैनात करेगा, और फिर इस प्लगइन के माध्यम से इसे पूछने में सक्षम है। –

4

जावा में, वक्तव्य (परिणाम नहीं) ओरेकल में कर्सर से संबंधित हैं। JVM और सिस्टम संसाधनों के संबंध में अप्रत्याशित व्यवहार के रूप में आपके द्वारा खोले जाने वाले संसाधनों को बंद करना सबसे अच्छा है।

इसके अतिरिक्त, कुछ जेडीबीसी पूलिंग पूल स्टेटमेंट्स और कनेक्शन फ्रेमवर्क करता है, इसलिए उन्हें बंद नहीं करना उन वस्तुओं को पूल में मुफ्त में चिह्नित नहीं कर सकता है, और ढांचे में प्रदर्शन के मुद्दों का कारण बन सकता है।

सामान्य रूप से, यदि किसी ऑब्जेक्ट पर एक करीबी() या नष्ट() विधि है, तो इसे कॉल करने का एक कारण है, और इसे अनदेखा करने के लिए अपने जोखिम पर ऐसा किया जाता है।

8

ओडीबीसी ब्रिज कुछ ओडीबीसी ड्राइवरों के साथ मेमोरी रिसाव का उत्पादन कर सकता है।

यदि आप एक अच्छा जेडीबीसी ड्राइवर का उपयोग करते हैं तो आपको कनेक्शन बंद करने में कोई समस्या नहीं होनी चाहिए। लेकिन 2 समस्याएं हैं:

  • क्या आपको पता है कि आपके पास कोई अच्छा ड्राइवर है या नहीं?
  • क्या आप भविष्य में अन्य जेडीबीसी ड्राइवरों का उपयोग करेंगे?

कि सबसे अच्छा अभ्यास यह सब बंद करना है।

19

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

public static void closeEverything(ResultSet rs, Statement stmt, 
     Connection con) { 
    if (rs != null) { 
     try { 
      rs.close(); 
     } catch (SQLException e) { 
     } 
    } 
    if (stmt != null) { 
     try { 
      stmt.close(); 
     } catch (SQLException e) { 
     } 
    } 
    if (con != null) { 
     try { 
      con.close(); 
     } catch (SQLException e) { 
     } 
    } 
} 
+6

मैन, शायद हमें एक क्लोजेबल इंटरफ़ेस की आवश्यकता है, हुह? – marcospereira

+2

जब आप स्टेटमेंट बंद करते हैं तो परिणामसेट स्वचालित रूप से बंद हो जाते हैं। (जावाडॉक http://download.oracle.com/javase/1.4.2/docs/api/java/sql/Statement.html देखें) –

+0

पोस्ट करने के लिए धन्यवाद। मुझे यह विचार पसंद है। – Abboq

8

मैं एक बड़ी J2EE वेब वातावरण में काम:

यहाँ एक उपयोगिता विधि है कि एक अंत में ब्लॉक से इस्तेमाल किया जा सकता है। हमारे पास कई डेटाबेस हैं जो एक ही अनुरोध में कनेक्ट हो सकते हैं। हमने अपने कुछ अनुप्रयोगों में लॉजिकल डेडलॉक्स प्राप्त करना शुरू कर दिया। मुद्दा यह था कि इस प्रकार है:

  1. उपयोगकर्ता पेज अनुरोध करेंगे
  2. सर्वर 1
  3. डीबी 1 पर सर्वर का चयन
  4. सर्वर डीबी जोड़ता है "बंद कर देता है" DB के लिए कनेक्शन 1
  5. सर्वर से कनेक्ट होता है डीबी 2
  6. डेडलॉक!

यह 2 कारणों से हुआ, हम सामान्य से अधिक यातायात का अनुभव कर रहे थे और डिफ़ॉल्ट रूप से जे 2 ईई स्पेक वास्तव में आपके कनेक्शन को तब तक बंद नहीं करता जब तक थ्रेड निष्पादन समाप्त नहीं हो जाता। तो, उपर्युक्त उदाहरण चरण 4 में वास्तव में कनेक्शन बंद नहीं हुआ, भले ही वे अंत में ठीक से बंद हो गए।

इसे ठीक करने के लिए, आपको अपने डेटाबेस कनेक्शन के लिए web.xml में संसाधन संदर्भों का उपयोग करना होगा और आपको res-sharing-scope को अदृश्य करने के लिए सेट करना होगा।

उदाहरण:

<resource-ref> 
    <description>My Database</description> 
    <res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name> 
    <res-type>javax.sql.DataSource</res-type> 
    <res-auth>Container</res-auth> 
    <res-sharing-scope>Unshareable</res-sharing-scope> 
</resource-ref>