स्टेटमेंट और रेडीस्टेडमेंट के बीच अंतर


222

तैयार स्टेटमेंट एक स्टेटमेंट का थोड़ा अधिक शक्तिशाली संस्करण है, और स्टेटमेंट के रूप में हमेशा कम से कम त्वरित और आसान होना चाहिए।
तैयार स्टेटमेंट पैराट्राइज्ड हो सकता है

अधिकांश रिलेशनल डेटाबेस चार चरणों में JDBC / SQL क्वेरी को हैंडल करते हैं:

  1. आने वाली SQL क्वेरी को पार्स करें
  2. SQL क्वेरी संकलित करें
  3. डेटा अधिग्रहण पथ की योजना / अनुकूलन करें
  4. अनुकूलित क्वेरी / अधिग्रहण और डेटा लौटाएँ

डेटाबेस में भेजे गए प्रत्येक SQL क्वेरी के लिए एक स्टेटमेंट हमेशा ऊपर दिए गए चार चरणों के माध्यम से आगे बढ़ेगा। एक तैयार स्टेटमेंट उपरोक्त निष्पादन प्रक्रिया में चरणों (1) - (3) को पूर्व-निष्पादित करता है। इस प्रकार, तैयार स्टेटमेंट बनाते समय कुछ पूर्व अनुकूलन तुरंत किया जाता है। प्रभाव निष्पादन समय में डेटाबेस इंजन पर लोड को कम करना है।

अब मेरा प्रश्न यह है कि - "क्या तैयार वक्तव्य का उपयोग करने का कोई अन्य लाभ है?"


12
मेरे अनुसार सबसे कुशल यह है कि आपकी क्वेरी को गतिशील रूप से
परिचालित

जवाबों:


198

एक के लाभ PreparedStatement:

  • SQL स्टेटमेंट का Precompilation और DB-साइड कैशिंग समग्र तेजी से निष्पादन और बैचों में समान SQL कथन का पुन: उपयोग करने की क्षमता की ओर जाता है ।

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

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    preparedStatement.setString(1, person.getName());
    preparedStatement.setString(2, person.getEmail());
    preparedStatement.setTimestamp(3, new Timestamp(person.getBirthdate().getTime()));
    preparedStatement.setBinaryStream(4, person.getPhoto());
    preparedStatement.executeUpdate();

    और इस तरह से स्ट्रिंग-कॉनसैनेटिंग द्वारा SQL स्ट्रिंग में मान को इनलाइन नहीं करते हैं

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'");
    preparedStatement.executeUpdate();
  • , जैसे किसी SQL स्ट्रिंग में अमानक जावा वस्तुओं की स्थापना के आसान बनाता है Date, Time, Timestamp, BigDecimal, InputStream( Blob) और Reader( Clob)। उन प्रकारों में से अधिकांश पर आप "बस" नहीं कर सकते हैं toString()जैसा कि आप एक साधारण में करते हैं Statement। आप इसे PreparedStatement#setObject()लूप के अंदर उपयोग करने के लिए भी रिफ्लेक्टर कर सकते हैं जैसा कि नीचे दी गई उपयोगिता विधि में दिखाया गया है:

    public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
        for (int i = 0; i < values.length; i++) {
            preparedStatement.setObject(i + 1, values[i]);
        }
    }

    जिसका उपयोग नीचे दिया जा सकता है:

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    setValues(preparedStatement, person.getName(), person.getEmail(), new Timestamp(person.getBirthdate().getTime()), person.getPhoto());
    preparedStatement.executeUpdate();

4
एक वर्णनात्मक और व्याख्यात्मक पाठ, संदर्भों और उदाहरण के साथ युग्मित, एक उत्कृष्ट उत्तर देता है। +1
XenoRo

1
@RD यह सच हो सकता है क्योंकि एक तैयार स्टेटमेंट के लिए डेटाबेस में 2 राउंड-ट्रिप की आवश्यकता होती है: पहला तैयार करना, दूसरा निष्पादित करना। हालांकि, मैं इसका परीक्षण करूंगा। मुझे लगता है कि इस योजना को अभी भी डेटाबेस सर्वर में कैश किया जाएगा Statement, लेकिन यह एक परीक्षण के लायक हो सकता है।
ब्रैंडन

2
मैं जावा के साथ सुनिश्चित करने के लिए नहीं कह सकता, लेकिन सामान्य तौर पर एक तैयार बयान "उद्धरण और अन्य विशेष पात्रों से बचने" का निर्माण नहीं करता है ; इसके बजाय, यह निष्पादन योग्य SQL और डेटा का पृथक्करण करता है , पैरामीटर को DBMS के अलग-अलग पैकेट के रूप में भेजता है क्योंकि SQL को क्वेरी प्लान में परिवर्तित किया गया है।
IMSoP

@ बालसैक - विस्तृत विवरण के लिए धन्यवाद।
कोडबी ..

49
  1. वे पूर्व-संकलित (एक बार) हैं, इसलिए गतिशील एसक्यूएल के दोहराए जाने के लिए तेजी से (जहां पैरामीटर बदलते हैं)

  2. डेटाबेस स्टेटमेंट कैशिंग डीबी निष्पादन प्रदर्शन को बढ़ा देता है

    डेटाबेस पहले निष्पादित कथनों के लिए निष्पादन योजनाओं के कैश को संग्रहीत करता है। यह डेटाबेस इंजन को पहले निष्पादित किए गए बयानों की योजनाओं का पुन: उपयोग करने की अनुमति देता है। चूंकि रेडीस्टेडमेंट पैरामीटर का उपयोग करता है, हर बार जब इसे निष्पादित किया जाता है तो यह एक ही एसक्यूएल के रूप में प्रकट होता है, डेटाबेस पिछली एक्सेस योजना का पुन: उपयोग कर सकता है, प्रसंस्करण को कम कर सकता है। स्टेटमेंट "इनलाइन" को SQL स्ट्रिंग में पैरामीटर बनाते हैं और इसलिए कैश के उपयोग को रोकने के लिए DB के समान SQL के रूप में प्रकट नहीं होते हैं।

  3. बाइनरी कम्यूनिकेशन प्रोटोकॉल का मतलब है कम बैंडविड्थ और डीबी सर्वर पर तेज़ कॉम्स कॉल

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

  4. वे प्रदान किए गए सभी पैरामीटर मानों के लिए पाठ से बचकर, SQL इंजेक्शन से बचाते हैं।

  5. वे क्वेरी कोड और पैरामीटर मान (संक्षिप्त SQL स्ट्रिंग्स की तुलना में) के बीच मजबूत पृथक्करण प्रदान करते हैं, पठनीयता को बढ़ाते हैं और कोड बनाए रखने वालों को क्वेरी के इनपुट और आउटपुट को जल्दी से समझने में मदद करते हैं।

  6. जावा में, getMetadata () और getParameterMetadata () को क्रमशः परिणाम सेट फ़ील्ड और पैरामीटर फ़ील्ड पर प्रतिबिंबित करने के लिए कॉल कर सकते हैं।

  7. जावा में, समझदारी से जावा ऑब्जेक्ट्स को पैरामीटर प्रकार के रूप में सेटओबजेक्ट, सेटबुलियन, सेटबाइट, सेटटेट, सेटडबल, सेटडब्लू, सेटफ्लोट, सेटआईओटी, सेटलॉन्ग, सेटहॉट, सेट टाइमस्टैम्प के माध्यम से स्वीकार करता है - यह जेडडीबीसी प्रकार के प्रारूप में परिवर्तित होता है जो डीबी के लिए समझ में आता है। () प्रारूप)।

  8. जावा में, SQL ARRAYs को सेट करता है, setArray विधि के माध्यम से पैरामीटर प्रकार के रूप में

  9. जावा में, क्रमशः CLBs, BLOBs, OutputStreams और Readers को पैरामीटर "फीड" के रूप में, setClob / setNClob, setBlob, setBinaryStream, setCharacterStream / setcciiStream / setNCharacterStream विधियों के माध्यम से स्वीकार करता है।

  10. जावा में, SQL-DATALINK, SQL ROWID, SQL XML, और NULL के माध्यम से setURL, setRowId, setSQLXML ans setNull विधियों के लिए DB-विशिष्ट मान सेट करने की अनुमति देता है

  11. जावा में, स्टेटमेंट से सभी तरीके विरासत में मिलते हैं। यह addBatch विधि को इनहेरिट करता है, और अतिरिक्त रूप से पैरामीटर मानों के एक सेट को addBatch विधि के माध्यम से बैच SQL कमांड के सेट से मिलान करने के लिए जोड़ा जाता है।

  12. जावा में, एक विशेष प्रकार की रेडीस्टेडमेंट (उपवर्ग कॉलटेस्टेमेंट) संग्रहीत प्रक्रियाओं को निष्पादित करने की अनुमति देता है - उच्च प्रदर्शन, एन्कैप्सुलेशन, प्रक्रियात्मक प्रोग्रामिंग और एसक्यूएल, डीबी प्रशासन / रखरखाव / तर्क का समर्थन, और मालिकाना डीबी तर्क और सुविधाओं का उपयोग


उन सभी चमत्कारों को कैसे संभव हो सकता है जब दोनों केवल इंटरफेस हैं?!?
राफेल

1
'अद्भुत' मानक कारखाने विधियों के माध्यम से संभव है जो इंटरफेस के कार्यान्वयन (विक्रेता-विशिष्ट) को वापस करते हैं: Connection.createStatement और Connection.prepareStatement। यह डिज़ाइन आपको इंटरफेस के खिलाफ काम करने के लिए मजबूर करता है, ताकि आपको विशिष्ट कार्यान्वयन कक्षाओं का पता न चले और ऐसे कार्यान्वयन वर्गों के साथ अनावश्यक तंग-युग्मन से बचें। सभी को जावा jdbc डॉक्स और जावा डॉक्स में उदाहरणों के साथ समझाया गया है। :)
बेस्ट

आपके "अंगूठे के एक नियम के रूप में" भाग का कोई मतलब नहीं है कि यह अन्य तरीकों से b के आसपास नहीं है
bhathiya-perera

38

PreparedStatementSQL इंजेक्शन के हमलों को रोकने में एक बहुत अच्छा बचाव (लेकिन मूर्ख नहीं) है । बाइंडिंग पैरामीटर मान एक अवांछित यात्रा करने वाले "छोटे बॉबी टेबल्स" के खिलाफ रखवाली करने का एक अच्छा तरीका है ।


6
फिर तैयार स्टेटमेंट के जरिए कोई SQL इंजेक्शन कैसे करेगा?
माइकल बोर्गवर्ड

2
माइकल, वेरिएबल्स को तैयार किए गए बयानों के तर्क के रूप में पारित किया गया, जो जेडीबीसी चालक द्वारा स्वचालित रूप से बच जाएगा।
कोडबी ..

3
क्या आप इस बात का उदाहरण दे सकते हैं कि SQL इंजेक्शन हमला किसी तैयार कथन के खिलाफ कैसे काम करेगा? क्या आप डेटाबेस कोड में बग मान रहे हैं?
पीटर रिको जूल

2
हां, लेकिन यह "सुंदर गूंगा" से बहुत परे है। यह मूर्खता उड़ाने वाला मन है। ज्ञान के एक औंस के साथ कोई भी ऐसा नहीं करेगा।
duffymo

2
इसके अलावा, कई डेटाबेस विक्रेता स्तंभ नाम (विचार ORDER BY) और / या संख्यात्मक स्थिरांक को कुछ स्थानों (विचार LIMIT, OFFSETऔर अन्य अंकन समाधान) में पैरामीटरिंग का समर्थन नहीं करते हैं , इसलिए SQL इंजेक्शन द्वारा इन पर हमला किया जा सकता है, तब भी जब तैयार स्टेटमेंट और पैरामीटरेशन का उपयोग कहीं भी किया जाता है मुमकिन।
dnet

31

स्टेटमेंट पर रेडीस्टेडमेंट के कुछ लाभ हैं:

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

SQL इंजेक्शन के बारे में और अधिक पढ़ें http://www.journaldev.com/2489/jdbc-statement-vs-preparedstatement-sql-injection-example पर


मैंने आपका लेख पढ़ा, वास्तव में अच्छा है। अब मेरा सवाल यह है कि कोई भी स्टेटमेंट का उपयोग क्यों करेगा ?! एक स्थिर क्वेरी के लिए भी ?!
पेड्रम बशीरी

मैं हमेशा ReadyedStatement का उपयोग करता हूं, मुझे किसी भी विशिष्ट परिदृश्य का पता नहीं है जहां स्टेटमेंट में अधिक लाभ हो सकता है।
पंकज

13

जोड़ने के लिए ज्यादा कुछ नहीं,

1 - यदि आप एक लूप में क्वेरी को निष्पादित करना चाहते हैं (1 से अधिक समय), तो तैयार किया गया कथन तेज हो सकता है, क्योंकि आपके द्वारा उल्लिखित अनुकूलन के कारण।

2 - SQL इंजेक्शन से बचने के लिए पैरामीटराइज्ड क्वेरी एक अच्छा तरीका है। Parameterized क्वेरी केवल ReadyedStatement में उपलब्ध हैं।


10

स्टेटमेंट स्टेटिक है और तैयार स्टेटमेंट डायनामिक है।

स्टेटमेंट डीडीएल के लिए उपयुक्त है और डीएमएल के लिए तैयार स्टेटमेंट।

स्टेटमेंट धीमा है जबकि तैयार स्टेटमेंट तेज है।

अधिक अंतर (संग्रहीत)


7

एक बयान में CLOBs नहीं कर सकते।

और: (OraclePreparedStatement) पीएस


7

जैसा कि मैटजम्स द्वारा उद्धृत किया गया है

JDBC में एक स्टेटमेंट का उपयोग DDL (ALTER, CREATE, GRANT, इत्यादि) के लिए किया जा रहा 100% स्थानीय होना चाहिए क्योंकि ये एकमात्र स्टेटमेंट प्रकार हैं जो BIND VARIABLES को स्वीकार नहीं कर सकते हैं। सभी प्रकार के बयान (डीएमएल, प्रश्न) के लिए तैयार किए गए स्टेस्टेमेंट या कॉल करने योग्य उपयोग किए जाने चाहिए। जैसा कि ये कथन प्रकार हैं जो बाइंड चर को स्वीकार करते हैं।

यह एक तथ्य है, एक नियम है, एक कानून है - तैयार किए गए कथनों का उपयोग करें। जहाँ कहीं भी स्थिति का उपयोग न करें।


5

तैयार किए गए बयान से sql इंजेक्शन को नजरअंदाज कर दिया जाता है, इसलिए तैयार बयान में सुरक्षा बढ़ जाती है


4
  • पढ़ना आसान है
  • आप आसानी से क्वेरी स्ट्रिंग को स्थिर बना सकते हैं

4

स्टेटमेंट का इस्तेमाल स्टेटिक एसक्यूएल स्टेटमेंट को निष्पादित करने के लिए किया जाएगा और यह इनपुट मापदंडों को स्वीकार नहीं कर सकता है।

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


4

तैयार या परिमाणित क्वेरी की एक और विशेषता: इस लेख से लिया गया संदर्भ।

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

स्टेटमेंट टेम्प्लेट तैयार किया जाता है और डेटाबेस सिस्टम को भेजा जाता है और डेटाबेस सिस्टम इस टेम्पलेट पर पार्सिंग, संकलन और अनुकूलन करता है और इसे निष्पादित किए बिना स्टोर करता है।

कुछ पैरामीटर जैसे कि, जहां टेम्पलेट टेम्प्लेट निर्माण के दौरान क्लॉज पास नहीं किया जाता है, बाद में इन मापदंडों को डेटाबेस सिस्टम को भेजते हैं और डेटाबेस सिस्टम SQL स्टेटमेंट के टेम्पलेट का उपयोग करते हैं और अनुरोध के अनुसार निष्पादित होते हैं।

एसक्यूएल इंजेक्शन के खिलाफ तैयार बयान बहुत उपयोगी होते हैं क्योंकि एप्लिकेशन विभिन्न तकनीकों और प्रोटोकॉल का उपयोग करके पैरामीटर तैयार कर सकता है।

जब डेटा की संख्या बढ़ रही है और उस समय सूचकांक लगातार बदल रहे हैं तो तैयार स्टेटमेंट विफल हो सकते हैं क्योंकि इस स्थिति में एक नई क्वेरी योजना की आवश्यकता होती है।


3

Statement इंटरफ़ेस मापदंडों के बिना स्थिर SQL स्टेटमेंट्स को निष्पादित करता है

PreparedStatement इंटरफ़ेस (विस्तार कथन) मापदंडों के साथ / बिना एक पूर्वनिर्धारित SQL कथन निष्पादित करता है

  1. बार-बार निष्पादन के लिए कुशल

  2. यह precompiled है इसलिए यह तेज है


2

न भ्रम पाएं: बस याद रखें

  1. स्टेटमेंट का उपयोग डीडीएल जैसे स्थिर प्रश्नों के लिए किया जाता है अर्थात डायनामिक क्वेरी अर्थात डीएमएल क्वेरी के लिए डीडीएल बना, ड्रॉप, बदल और तैयार किया जाता है।
  2. बयान में, क्वेरी तैयार नहीं की गई है जबकि तैयारी में क्वेरी को पूर्व-निर्धारित किया गया है, क्योंकि इस तैयारी के लिए समय कुशल है।
  3. तैयार स्टेटमेंट निर्माण के समय तर्क लेता है जबकि स्टेटमेंट तर्क नहीं लेता है। उदाहरण के लिए यदि आप तालिका बनाना चाहते हैं और तत्व सम्मिलित करना चाहते हैं तो :: स्टेटमेंट और इंसर्ज़ तत्व (डायनामिक) का उपयोग करके तालिका (स्थैतिक) बनाएँ।

1
तैयार कथन के समय तर्क लेता है जबकि स्टेटमेंट में तर्क नहीं होते हैं?

1

- मैं का उपयोग कर एक काम विरासत कोड बदलने के लिए इस सवाल का जवाब सब का पालन किया Statement(लेकिन एसक्यूएल इंजेक्शन वाले) एक समाधान करने के लिए का उपयोग कर PreparedStatementके आसपास अर्थ विज्ञान के गरीब समझ की वजह से एक बहुत धीमी कोड के साथ Statement.addBatch(String sql)औरPreparedStatement.addBatch()

इसलिए मैं अपने परिदृश्य को यहां सूचीबद्ध कर रहा हूं, ताकि अन्य लोग एक ही गलती न करें।

मेरा परिदृश्य था

Statement statement = connection.createStatement();

for (Object object : objectList) {
    //Create a query which would be different for each object 
    // Add this query to statement for batch using - statement.addBatch(query);
}
statement.executeBatch();

इसलिए उपरोक्त कोड में, मेरे पास हजारों अलग-अलग प्रश्न थे, सभी ने एक ही बयान में जोड़ा और इस कोड ने तेजी से काम किया क्योंकि कैश नहीं होने वाले बयान अच्छे थे और इस कोड को ऐप में शायद ही कभी निष्पादित किया गया था।

SQL इंजेक्शन को ठीक करने के लिए, मैंने इस कोड को बदल दिया है

List<PreparedStatement> pStatements = new ArrayList<>();    
for (Object object : objectList) {
    //Create a query which would be different for each object 
    PreparedStatement pStatement =connection.prepareStatement(query);
    // This query can't be added to batch because its a different query so I used list. 
    //Set parameter to pStatement using object 
    pStatements.add(pStatement);
}// Object loop
// In place of statement.executeBatch(); , I had to loop around the list & execute each update separately          
for (PreparedStatement ps : pStatements) {
    ps.executeUpdate();
}

तो आप देखते हैं, मैंने हजारों PreparedStatementऑब्जेक्ट बनाना शुरू कर दिया है और फिर अंततः बैचिंग का उपयोग करने में सक्षम नहीं है क्योंकि मेरे परिदृश्य ने मांग की है कि - हजारों अपडेट या इन्सर्ट प्रश्न हैं और इनमें से सभी प्रश्न अलग-अलग होते हैं।

प्रदर्शन में गिरावट के बिना किसी भी कीमत पर SQL इंजेक्शन को ठीक करना अनिवार्य था और मुझे नहीं लगता कि यह PreparedStatementइस परिदृश्य में संभव है।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.