एक तैयारी तैयार करना कई बार पुन: उपयोग करना


96

किसी भी पूल के बिना एक ही सामान्य कनेक्शन के साथ रेडीस्टेडमेंट का उपयोग करने के मामले में, क्या मैं प्रत्येक डीएमएल / एसक्यूएल ऑपरेशन के लिए एक उदाहरण को फिर से तैयार कर सकता हूं, जो तैयार किए गए बयानों की शक्ति को नियंत्रित करता है?

मेरा मतलब:

for (int i=0; i<1000; i++) {
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
    preparedStatement.close();
}

के बजाय:

PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i=0; i<1000; i++) {
    preparedStatement.clearParameters();
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
}
preparedStatement.close();

मेरा प्रश्न इस तथ्य से उत्पन्न होता है कि मैं इस कोड को एक बहुआयामी वातावरण में रखना चाहता हूं, क्या आप मुझे कुछ सलाह दे सकते हैं? धन्यवाद


तो आपकी क्वेरी, sqlलूप में नहीं बदलती है? यदि वह क्वेरी लूप के प्रत्येक पुनरावृत्ति के लिए नहीं बदल रही है, तो आप PreparedStatementप्रत्येक पुनरावृत्ति (पहले कोड स्निप में) के लिए एक नया क्यों बना रहे हैं ? क्या ऐसा करने का कोई कारण है?
साबिर खान

यदि क्वेरी बदल रही है, तो फिर भी दूसरा तरीका बेहतर है? कोई नुकसान?
स्टनर

जवाबों:


144

दूसरा तरीका अधिक कुशल है, लेकिन एक बेहतर तरीका यह है कि उन्हें बैचों में निष्पादित किया जाए:

public void executeBatch(List<Entity> entities) throws SQLException { 
    try (
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL);
    ) {
        for (Entity entity : entities) {
            statement.setObject(1, entity.getSomeProperty());
            // ...

            statement.addBatch();
        }

        statement.executeBatch();
    }
}

हालाँकि आप JDBC ड्राइवर कार्यान्वयन पर निर्भर हैं कि आप एक साथ कितने बैचों को निष्पादित कर सकते हैं। उदाहरण के लिए आप उन्हें हर 1000 बैचों को निष्पादित करना चाहते हैं:

public void executeBatch(List<Entity> entities) throws SQLException { 
    try (
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL);
    ) {
        int i = 0;

        for (Entity entity : entities) {
            statement.setObject(1, entity.getSomeProperty());
            // ...

            statement.addBatch();
            i++;

            if (i % 1000 == 0 || i == entities.size()) {
                statement.executeBatch(); // Execute every 1000 items.
            }
        }
    }
}

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

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

public void executeBatch(List<Entity> entities) throws SQLException { 
    try (Connection connection = dataSource.getConnection()) {
        connection.setAutoCommit(false);

        try (PreparedStatement statement = connection.prepareStatement(SQL)) {
            // ...

            try {
                connection.commit();
            } catch (SQLException e) {
                connection.rollback();
                throw e;
            }
        }
    }
}

inside the same method block- आप का अर्थ है कि प्रत्येक थ्रेड का अपना स्टैक होगा और ये कनेक्शन और स्टेटमेंट एक तरफ से स्टैक में होते हैं और दूसरे डेटा स्रोत से निष्पादन की प्रत्येक नई कॉल (== हर थ्रेड) कनेक्शन के अलग-अलग उदाहरण देंगे। क्या मैं आपको सही समझ रहा हूँ? ”
पावेल_के

मैं पहली विधि कर रहा हूं लेकिन SQL प्रोफाइलर में निगरानी करते समय मैं एक के बजाय कई तैयार किए गए बयानों को बार-बार देखता हूं। मैं यह पता नहीं लगा सका कि यह कई बयान क्यों दिखा रहा है। सहायता की आवश्यकता है।
दुष्ट लाड

आपका उत्तर अच्छा है बशर्ते क्वेरी लूप में नहीं बदल रही है .. क्या होगा यदि क्वेरी बदल रही है उदाहरण के लिए मेरे मामले में जहां क्वेरी बदली गई है .. मुझे लगता है कि अभी भी दूसरा दृष्टिकोण बेहतर है। कृपया मान्य करें
स्टनर

13

आपके कोड में लूप केवल एक अधिक सरलीकृत उदाहरण है, है ना?

PreparedStatementकेवल एक बार बनाना बेहतर होगा , और इसे फिर से लूप में फिर से उपयोग करना होगा।

उन स्थितियों में जहां यह संभव नहीं है (क्योंकि यह प्रोग्राम प्रवाह को बहुत अधिक जटिल करता है), यह अभी भी एक का उपयोग करने के लिए फायदेमंद है PreparedStatement, भले ही आप इसे केवल एक बार उपयोग करें, क्योंकि काम का सर्वर-पक्ष (SQL को पार्स करना और निष्पादन को कैशिंग करना) योजना), अभी भी कम हो जाएगा।

उस स्थिति को संबोधित करने के लिए जिसे आप जावा-साइड का फिर से उपयोग करना चाहते हैं PreparedStatement, कुछ JDBC ड्राइवरों (जैसे Oracle) में एक कैशिंग सुविधा है: यदि आप PreparedStatementउसी कनेक्शन पर उसी SQL के लिए बनाते हैं , तो यह आपको वही देगा (कैशेड ) उदाहरण है।

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


1
वास्तव में कनेक्शन का अपना विशिष्ट धागा होता है और इसमें प्रत्येक कथन निष्पादित किया जाता है, लेकिन मैं तैयार किए गए कथनों के एक उजागर ढेर के माध्यम से उस धागे तक पहुंचता हूं। इसलिए अन्य समवर्ती धागे शुरू में केवल सभी तैयार किए गए बयानों को बनाने के लिए आवश्यक पैरामेट्स पास करते हैं, लेकिन फिर वे समांतर रूप से संशोधित कर सकते हैं
स्टील प्लम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.