JDBC परिणाम और विवरण अलग-अलग बंद होने चाहिए, हालांकि कनेक्शन बाद में बंद हो गया है?


256

कहा जाता है कि उपयोग के बाद सभी JDBC संसाधनों को बंद करना एक अच्छी आदत है। लेकिन अगर मेरे पास निम्नलिखित कोड है, तो क्या Resultset और कथन को बंद करना आवश्यक है?

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = // Retrieve connection
    stmt = conn.prepareStatement(// Some SQL);
    rs = stmt.executeQuery();
} catch(Exception e) {
    // Error Handling
} finally {
    try { if (rs != null) rs.close(); } catch (Exception e) {};
    try { if (stmt != null) stmt.close(); } catch (Exception e) {};
    try { if (conn != null) conn.close(); } catch (Exception e) {};
}

सवाल यह है कि यदि कनेक्शन बंद करना काम करता है या यदि यह उपयोग में कुछ संसाधनों को छोड़ देता है।


जवाबों:


199

आपने जो किया है वह सही और बहुत अच्छा अभ्यास है।

इसका कारण मैं इसका अच्छा अभ्यास बताता हूं ... उदाहरण के लिए, यदि किसी कारण से आप डेटाबेस पूलिंग के "आदिम" प्रकार का उपयोग कर रहे हैं और आप कॉल करते हैं connection.close(), तो कनेक्शन पूल में वापस आ जाएगा और ResultSet/ Statementकभी बंद नहीं होगा और फिर आप कई अलग अलग नई समस्याओं में चलेगा!

तो तुम हमेशा connection.close()साफ करने के लिए पर भरोसा नहीं कर सकते ।

आशा है कि ये आपकी मदद करेगा :)


4
... और स्पष्ट रूप से सब कुछ बंद करने का सबसे स्पष्ट कारण।
Zeemee

2
मैं सहमत हूं कि परिणाम सेट और बयानों को बंद करना अच्छा है। हालांकि, परिणाम सेट और स्टेटमेंट कचरा एकत्र किए जाते हैं - वे हमेशा के लिए खुले नहीं रहते हैं और आप "कई अलग-अलग नई समस्याओं में नहीं चलते हैं"।
स्टीफन

3
@ राल्फ स्टीवंस - आप उस पर भरोसा नहीं कर सकते। मेरे पास एक ऐसी स्थिति है जहां MSSQL JDBC ड्राइवर ने मेमोरी को लीक कर दिया है क्योंकि ResultSet को बंद किए जाने के बाद भी बंद नहीं किया गया था।
पॉल

7
@Paul - दिलचस्प। यह मुझे JDBC ड्राइवर की कमी की तरह लगता है।
स्टीफन

2
@ माइक्रब - यह उम्मीद के मुताबिक काम करेगा। हालांकि सिद्धांत रूप में, अपवाद "महंगे" हैं, इसलिए एक बहुत छोटा प्रदर्शन दस्तक होगा (जिसे आपने पहले ही पहचान लिया है)
पॉल

124

जावा 1.7 हमारे जीवन बहुत आसान बना देता है धन्यवाद कोशिश के साथ-संसाधनों बयान

try (Connection connection = dataSource.getConnection();
    Statement statement = connection.createStatement()) {
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do stuff with the result set.
    }
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do more stuff with the second result set.
    }
}

यह वाक्य रचना काफी संक्षिप्त और सुरुचिपूर्ण है। और connectionवास्तव में जब भी statementनहीं बनाया जा सकता है तब भी बंद रहेगा।


56
आपको इस तरह घोंसला बनाने की आवश्यकता नहीं है, आप यह सब एक कोशिश के साथ संसाधनों में कर सकते हैं, बस संसाधन घोषणाओं को अलग-अलग बयानों (अलग-अलग ;)
के रूप में मानें

2
मार्क रोटेटेवेल: आप सभी तीन कनेक्शन, स्टेटमेंट और रिजल्टसेट के लिए एक ही प्रयास का उपयोग कर सकते हैं, लेकिन यदि आप कई क्वेरी करना चाहते हैं, तो नई क्वेरी शुरू करने से पहले आपको पिछले रिजल्टसेट को बंद कर देना चाहिए। कम से कम यही तरीका है कि मैं जिस DBMS का उपयोग कर रहा था, वह कैसे काम करता है।
राउल सालिनास-मोंटियागुडो

आप ऐसा कुछ क्यों नहीं करेंगे? कोशिश (खुला कनेक्शन) {कोशिश (कई बयान और परिणाम) {खासकर जब अगले प्रश्न पिछले लोगों के साथ गणना कर सकते हैं।
डैनियल हजडुक

डैनियल: जब मैंने उस पैटर्न का उपयोग किया था, तो अंतर्निहित जेडीबीसी बैकएंड ने एक रिजल्टसेट खोलने और दूसरे को खोलने का समर्थन नहीं किया।
राउल सालिनास-मोंटेगूडो

rascio, आप जो कुछ भी पकड़ ब्लॉक में कर सकते हैं
राउल सालिनास-मोंटियागुडो

73

से javadocs :

जब कोई Statementवस्तु बंद होती है, तो उसकी वर्तमान ResultSetवस्तु, यदि कोई मौजूद है, भी बंद हो जाती है।

हालाँकि, जब आप अंतर्निहित को बंद करते हैं , तो javadocs बहुत स्पष्ट नहीं होती है Statementऔर ResultSetबंद हो जाती है Connection। वे बस कहते हैं कि एक कनेक्शन को बंद करना:

इस Connectionऑब्जेक्ट के डेटाबेस और JDBC संसाधनों को तुरंत रिलीज़ होने की प्रतीक्षा करने के बजाय तुरंत जारी करता है।

मेरी राय में, हमेशा स्पष्ट रूप से करीब ResultSets, Statementsऔर Connectionsजब आप उनके साथ समाप्त हो जाते हैं, तो कार्यान्वयन के रूप में closeडेटाबेस ड्राइवरों के बीच भिन्न हो सकते हैं।

आप अपने आप को इस तरह के रूप तरीकों का उपयोग करके बॉयलर-प्लेट कोड का एक बहुत कुछ बचा सकता है closeQuietlyमें DBUtils अपाचे से।


1
धन्यवाद डॉगबेन। मुद्दा यह है कि आप Connection.close के कार्यान्वयन पर निर्भर नहीं हो सकते हैं, है ना?
ज़ीमी

1
मेरे जैसे n00bs के लिए साइड नोट - stackoverflow.com/questions/3992199/what-is-boilerplate-code
david blaine

39

अब मैं जावा के साथ Oracle का उपयोग कर रहा हूं। यहाँ मेरा नज़रिया है:

आपको बंद करना चाहिए ResultSetऔर Statementस्पष्ट रूप से करना चाहिए क्योंकि ओरेकल को कनेक्शन बंद करने के बाद भी कर्सर को खुला रखने में समस्या है। यदि आप ResultSet(कर्सर) को बंद नहीं करते हैं तो यह एक त्रुटि को फेंक देगा जैसे अधिकतम खुले कर्सर पार हो गए हैं

मुझे लगता है कि आप अन्य डेटाबेस के साथ एक ही समस्या का सामना कर सकते हैं।

जब समाप्त हो जाता है तो ट्यूटोरियल बंद करें परिणाम :

समाप्त होने पर परिणाम बंद करें

बंद ResultSetजल्द ही आप के साथ काम करना समाप्त करने के रूप में के रूप में वस्तु ResultSetवस्तु भले ही Statementवस्तु बंद कर देता है ResultSetपरोक्ष वस्तु जब यह बंद कर देता है, को बंद करने ResultSetको स्पष्ट रूप से जल्दी संभव के रूप में याद करने के लिए स्मृति कचरा कलेक्टर को मौका देता है क्योंकि ResultSetवस्तु क्वेरी के आधार पर स्मृति के बहुत पर कब्जा कर सकते।

ResultSet.close();


धन्यवाद हीरालाल, ये जल्दी से जल्दी इसे बंद करने के अच्छे कारण हैं। हालांकि, क्या इससे कोई फर्क नहीं पड़ता कि क्या कनेक्शन से पहले ResultSet और कथन को बंद कर दिया गया है (कुछ मामलों में इसका मतलब है: जितनी जल्दी हो सके नहीं)?
ज़ीमी

यदि आप कनेक्शन बंद करते हैं, तो यह सभी

और मुझे कनेक्शन से पहले परिणामसेट क्यों बंद करना चाहिए? तुम क्योंकि ओरेकल चालक समस्याओं का मतलब है?
ज़ीमी

1
यहाँ अधिक सामान्य स्पष्टीकरण है :) stackoverflow.com/questions/103938/…

सिद्धांत रूप में, यदि आप कथन को बंद करते हैं, तो आपको परिणाम को बंद नहीं करना है, लेकिन यह शायद अच्छा अभ्यास है।
रॉगरडपैक

8

यदि आप अधिक कॉम्पैक्ट कोड चाहते हैं, तो मैं Apache Commons DbUtils का उपयोग करने का सुझाव देता हूं । इस मामले में:

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = // Retrieve connection
    stmt = conn.prepareStatement(// Some SQL);
    rs = stmt.executeQuery();
} catch(Exception e) {
    // Error Handling
} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(stmt);
    DbUtils.closeQuietly(conn);
}

3
यदि मैं rs.close (), stmt.close (), conn.close ()
Onkar Musale

3

JDBC के साथ जुड़े संसाधनों को बंद करने की सही और सुरक्षित विधि यह ( JDBC संसाधन को बंद करने से कैसे लिया जाए - हर बार ):

Connection connection = dataSource.getConnection();
try {
    Statement statement = connection.createStatement();

    try {
        ResultSet resultSet = statement.executeQuery("some query");

        try {
            // Do stuff with the result set.
        } finally {
            resultSet.close();
        }
    } finally {
        statement.close();
    }
} finally {
    connection.close();
}

3

कोई फर्क नहीं पड़ता कि Connectionपूल करने योग्य है या नहीं। यहां तक ​​कि पूल में लौटने से पहले पूल करने योग्य कनेक्शन को साफ करना पड़ता है।

"क्लीन" का अर्थ आमतौर पर परिणाम को बंद करना और किसी भी लंबित लेनदेन को वापस करना है लेकिन कनेक्शन को बंद नहीं करना है। अन्यथा पूलिंग अपनी समझ खो देता है।


2

नहीं, आपको कनेक्शन बंद करने के लिए कुछ भी आवश्यक नहीं है। किसी भी उच्च वस्तु को बंद करने पर प्रति JDBC चश्मा स्वचालित रूप से निचली वस्तुओं को बंद कर देगा। कनेक्शन Connectionबंद करने से कोई भी बंद हो जाएगा Statement। किसी Statementको भी बंद करने से ResultSetउसके द्वारा बनाए गए सभी s बंद हो जाएंगे Statement। कोई फर्क नहीं पड़ता कि Connectionपूल करने योग्य है या नहीं। यहां तक ​​कि पूल में लौटने से पहले पूल करने योग्य कनेक्शन को भी साफ करना पड़ता है।

बेशक, आपके पास Connectionबहुत सारे बयान देने वाले लंबे नेस्टेड लूप हो सकते हैं , फिर उन्हें बंद करना उचित है। मैं लगभग कभी बंद ResultSetनहीं करता, हालांकि बंद होने पर Statementया Connectionउन्हें बंद करने पर अत्यधिक लगता है।


1

मैंने पुन: प्रयोज्य वन लाइनर बनाने के लिए निम्न विधि बनाई:

public void oneMethodToCloseThemAll(ResultSet resultSet, Statement statement, Connection connection) {
    if (resultSet != null) {
        try {
            if (!resultSet.isClosed()) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if (statement != null) {
        try {
            if (!statement.isClosed()) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    if (connection != null) {
        try {
            if (!connection.isClosed()) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

मैं इस कोड का उपयोग एक अभिभावक वर्ग के लिए करता हूं जो मेरे सभी वर्गों को विरासत में मिला है जो डीबी क्वेरी भेजते हैं। मैं सभी Queries पर Oneliner का उपयोग कर सकता हूं, भले ही मेरे पास परिणाम नहीं हो। विधि सही क्रम में ResultSet, कथन, कनेक्शन को बंद करने का ख्याल रखती है। यह वही है जो मेरा अंत ब्लॉक दिखता है।

finally {
    oneMethodToCloseThemAll(resultSet, preStatement, sqlConnection);
}

-1

जहाँ तक मुझे याद है, वर्तमान JDBC में, परिणाम और कथन AutoCloseable इंटरफ़ेस को लागू करते हैं। इसका मतलब है कि वे नष्ट होने या दायरे से बाहर जाने पर अपने आप बंद हो जाते हैं।


3
नहीं, इसका मतलब केवल यह है कि closeकोशिश-के-संसाधनों के बयान के अंत में कहा जाता है। Docs.oracle.com/javase/tutorial/essential/exception/… और docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html देखें ।
ज़ीमी

-1

कुछ सुविधा कार्य:

public static void silentCloseResultSets(Statement st) {
    try {
        while (!(!st.getMoreResults() && (st.getUpdateCount() == -1))) {}
    } catch (SQLException ignore) {}
}
public static void silentCloseResultSets(Statement ...statements) {
    for (Statement st: statements) silentCloseResultSets(st);
}

यहां ऐसा कुछ भी नहीं है जो कुछ भी बंद कर दे। बस एक व्यर्थ लूप जो बेकार में पूरी प्रतिक्रिया को पढ़ता है, भले ही यह स्पष्ट रूप से कोई और नहीं चाहता है।
लोर्ने की मार

-1

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

try {
    //...   
    return resp;
} finally {
    if (rs != null && !rs.isClosed()) {
        try {
            rs.close();
        } catch (Exception e2) { 
            log.warn("Cannot close resultset: " + e2.getMessage());
        }
    }
    if (stmt != null && !stmt.isClosed()) {
        try {
            stmt.close();
        } catch (Exception e2) {
            log.warn("Cannot close statement " + e2.getMessage()); 
        }
    }
    if (con != null && !conn.isClosed()) {
        try {
            con.close();
        } catch (Exception e2) {
            log.warn("Cannot close connection: " + e2.getMessage());
        }
    }
}

सिद्धांत रूप में, यह 100% सही नहीं है क्योंकि चेकिंग के बीच में करीबी राज्य और पास में ही राज्य के लिए परिवर्तन के लिए बहुत कम जगह है। सबसे खराब स्थिति में आपको लंबे समय तक चेतावनी मिलेगी। - लेकिन यह लंबी अवधि के प्रश्नों में राज्य परिवर्तन की संभावना से कम है। हम इस पैटर्न का उपयोग "एवरेज" लोड (150 एक साथ उपयोगकर्ता) के साथ कर रहे हैं और हमें इसके साथ कोई समस्या नहीं थी - इसलिए उस चेतावनी संदेश को कभी न देखें।


आपको isClosed()परीक्षणों की आवश्यकता नहीं है , क्योंकि इनमें से कोई भी जो पहले से बंद है, को बंद करना एक नो-ऑप है। जो टाइमिंग विंडो की समस्या को खत्म करता है। जिसे Connection, Statementऔर ResultSetस्थानीय चर बनाकर भी समाप्त किया जाएगा ।
लोर्न
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.