এসকিউএলে স্ট্রিংবিল্ডার ব্যবহারের সঠিক উপায়


88

আমি আমার প্রোজেক্টে সবেমাত্র কিছু স্কয়ার কোয়েরি বিল্ডটি পেয়েছি:

return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString();

এটি কি StringBuilderতার লক্ষ্য অর্জন করে, অর্থাত্ স্মৃতি ব্যবহার হ্রাস করে?

আমি সন্দেহ করি, কারণ কনস্ট্রাক্টরে '+' (স্ট্রিং কনক্যাট অপারেটর) ব্যবহার করা হয়। নীচের কোডটির মতো স্ট্রিং ব্যবহার করার মতো কি একই পরিমাণ মেমোরি লাগবে? s আমি বুঝতে পেরেছি, এটি ব্যবহার করার সময় পৃথক হয় StringBuilder.append()

return "select id1, " + " id2 " + " from " + " table";

উভয় বিবৃতি মেমরি ব্যবহারে সমান বা না? পরিষ্কার করে বলো.

আগাম ধন্যবাদ!

সম্পাদনা করুন:

বিটিডাব্লু, এটি আমার কোড নয় । এটি একটি পুরানো প্রকল্পে পাওয়া গেছে। এছাড়াও, কোয়েরিটি আমার উদাহরণের মতো এতটা ছোট নয়। :)


4
এসকিউএল সুরক্ষা: সর্বদা ব্যবহার করুন PreparedStatementবা অনুরূপ কিছু: ডকস.ওরকল
ক্রিস্টোফ

মেমোরি ব্যবহারের জিনিসটি বাদ দিয়ে কেন এসকিউএল বিল্ডার লাইব্রেরি ব্যবহার করবেন না: স্ট্যাকওভারফ্লো.com
লুকাশ

উত্তর:


182

স্ট্রিংবিল্ডার ব্যবহারের লক্ষ্য, অর্থাৎ স্মৃতিশক্তি হ্রাস করা। এটি অর্জন করা হয়?

একদম না. এই কোডটি StringBuilderসঠিকভাবে ব্যবহার করছে না। (আমি মনে করি আপনি এটি ভুলভাবে লিখেছেন, যদিও এর চারপাশে অবশ্যই উদ্ধৃতি নেই id2এবং table?)

নোট করুন যে লক্ষ্যটি (সাধারণত) ব্যবহৃত মোট মেমরির চেয়ে মেমরি মন্থকে কমিয়ে আনা , আবর্জনা সংগ্রহকারীকে জীবন কিছুটা সহজ করে তোলা।

নীচের মত স্ট্রিং ব্যবহার করার জন্য কি মেমরির সমান হবে?

না, এটি আপনার উদ্ধৃত সোজা কন্টাক্টের চেয়ে আরও মেমরি মন্থনের কারণ হবে । (যতক্ষণ না / না পর্যন্ত JVM অপ্টিমাইজার দেখতে পায় যে কোডটিতে স্পষ্টত StringBuilderঅপ্রয়োজনীয় এবং এটি যদি সম্ভব হয় তবে এটি অপ্টিমাইজ করে))

যদি এই কোডটির লেখক ব্যবহার করতে চান StringBuilder(এর পক্ষে যুক্তিও রয়েছে, তবে এর বিরুদ্ধেও রয়েছে; এই উত্তরটির শেষে নোট দেখুন) সঠিকভাবে এটি করা ভাল (এখানে আমি ধরে নিচ্ছি যে এর চারপাশে আসলে উদ্ধৃতিগুলি নেই id2এবং table):

StringBuilder sb = new StringBuilder(some_appropriate_size);
sb.append("select id1, ");
sb.append(id2);
sb.append(" from ");
sb.append(table);
return sb.toString();

নোট যে আমি তালিকাভুক্ত করেছি some_appropriate_sizeমধ্যে StringBuilderকন্সট্রাকটর, যাতে পুরো বিষয়বস্তু আমরা সংযোজন করতে যাচ্ছেন জন্য যথেষ্ট ক্ষমতা আউট শুরু হয়। আপনি যদি কোনও 16 টি অক্ষর নির্দিষ্ট না করেন তবে ডিফল্ট আকারটি ব্যবহৃত হয় যা সাধারণত খুব ছোট হয় এবং StringBuilderনিজেকে বড় করে তোলার জন্য পুনঃনির্ধারণ করতে হয় (আইআইআরসি, সান / ওরাকল জেডিকে তে, এটি নিজেই দ্বিগুণ হয় [বা আরও বেশি, যদি এটি জানে যে appendপ্রতিবার ঘরটি শেষ হয়ে গেলে] কোনও নির্দিষ্ট সন্তুষ্ট করার জন্য এটি আরও বেশি প্রয়োজন ।

আপনি শুনেছেন যে সান / ওরাকল সংকলক দিয়ে সংকলিত হলে স্ট্রিং কনটেনটেশন কভারগুলির নীচে একটি ব্যবহার করবেStringBuilder । এটি সত্য, এটি StringBuilderসামগ্রিক প্রকাশের জন্য একটি ব্যবহার করবে । তবে এটি ডিফল্ট কনস্ট্রাক্টর ব্যবহার করবে, যার অর্থ বেশিরভাগ ক্ষেত্রে এটি পুনর্বিবেচনা করতে হবে। যদিও এটি পড়া সহজ। মনে রাখবেন যে এটি কয়েকটি ধারাবাহিক প্রতিযোগিতার ক্ষেত্রে সত্য নয় । উদাহরণস্বরূপ, এটি একটি ব্যবহার করে :StringBuilder

return "prefix " + variable1 + " middle " + variable2 + " end";

এটি মোটামুটি অনুবাদ করে:

StringBuilder tmp = new StringBuilder(); // Using default 16 character size
tmp.append("prefix ");
tmp.append(variable1);
tmp.append(" middle ");
tmp.append(variable2);
tmp.append(" end");
return tmp.toString();

সুতরাং এটি ঠিক আছে, যদিও ডিফল্ট নির্মাতা এবং পরবর্তী পুনঃনির্ধারণ (গুলি) আদর্শ না হলেও প্রতিকূলতা এটি যথেষ্ট ভাল - এবং উপসংহারটি আরও অনেক বেশি পাঠযোগ্য।

তবে এটি কেবল একটি একক অভিব্যক্তির জন্য। একাধিক StringBuilderগুলি এর জন্য ব্যবহৃত হয়:

String s;
s = "prefix ";
s += variable1;
s += " middle ";
s += variable2;
s += " end";
return s;

এটি এইরকম কিছু হয়ে ওঠে:

String s;
StringBuilder tmp;
s = "prefix ";
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable1);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" middle ");
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable2);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" end");
s = tmp.toString();
return s;

... যা বেশ কুৎসিত।

তবে এটি মনে রাখা গুরুত্বপূর্ণ, খুব কম ক্ষেত্রেই এটি গুরুত্বপূর্ণ নয় এবং পাঠযোগ্যতার সাথে চলে যা (যা রক্ষণাবেক্ষণকে বাড়ায়) একটি নির্দিষ্ট পারফরম্যান্স ইস্যু বাদ দিয়ে পছন্দ করা হয়।


ঠিক আছে, এটি আরও ভাল। প্যারামিটারলেস কনস্ট্রাক্টর ব্যবহারটি সামান্য দুর্ভাগ্যজনক, তবে তাৎপর্যপূর্ণ হওয়ার সম্ভাবনা কম। এটি তাত্পর্যপূর্ণ সমস্যা হতে পারে এমন সন্দেহ করার উপযুক্ত কারণ না থাকলে আমি এখনও একক x + y + zঅভিব্যক্তি ব্যবহার StringBuilderকরব।
জন স্কিটি

@ ক্রাউডার আরও একটি সন্দেহ আছে। StringBuilder sql = new StringBuilder(" XXX); sql.append("nndmn");...। অনুরূপ sql.appendলাইন 60 লাইনের কাছাকাছি। এই ভাল?
ভান্দু

4
@ বনাথী: ("প্রশ্ন", "সন্দেহ" নয় - এটি একটি সাধারণ ভুল ব্যাখ্যা) It's এটি ঠিক আছে তবে সম্ভবত একাধিক পুনর্নির্মাণের ফলাফল StringBuilderহবে কারণ আপনি প্রথমে কনস্ট্রাক্টর ১ plus টি অক্ষরের পাশ দিয়ে যাওয়ার স্ট্রিংয়ের জন্য প্রাথমিকভাবে ইচ্ছাশক্তি বরাদ্দ করা হবে। সুতরাং আপনি যদি 16 টিরও বেশি অক্ষর সংযোজন করেন (আমি সাহসী হলাম আপনি, যদি 60 টি সংযোজন থাকে!), StringBuilderকমপক্ষে একবার এবং সম্ভবত বহুবার পুনর্বিবেচনা করতে হবে। আপনি যদি একটি যুক্তিসঙ্গত ধারণা কত বড় শেষ ফল কী হবে (বলে 400 অক্ষর) থাকে, তাহলে তা করতে সেরা sql = new StringBuilder(400);(অথবা যাই হোক না কেন) তাহলে কি appendসে।
টিজে ক্রোডার

@ বনানী: খুশি যে সাহায্য করেছে। হ্যাঁ, যদি এটি ,000,০০০ অক্ষর হতে চলেছে, তা StringBuilderআগেই বলেছিল যে প্রায় আটটি মেমরি রিলোকেশনগুলি সাশ্রয় হবে (প্রাথমিক স্ট্রিংটি প্রায় 10 টি অক্ষর হিসাবে ধরে নেওয়া হচ্ছে, এসবি 26 টি দিয়ে শুরু হবে, তারপরে দ্বিগুণ হবে 52, তারপর 104, 208, 416, 832, 1664, 3328, এবং শেষ পর্যন্ত 6656)। শুধুমাত্র এটি যদি হটস্পট হয় তবে তাৎপর্যপূর্ণ তবে আপনি যদি আগে থেকে জানেন ... :-)
টিজে ক্রোডার

@ টিজে ক্রাউডার আপনি বলতে চাইছেন আরও ভাল পারফরম্যান্সের জন্য আমাকে "+" অপারেটরটি ব্যবহার করা উচিত নয়। ঠিক? তাহলে ওরাকাল কেন তাদের ভাষায় "+" অপারেটর যুক্ত করেছেন আপনি দয়া করে বিশদ বিবরণ করতে পারেন? যেভাবেই আপনার উত্তরের জন্য আমার আপভেট করুন।
স্মিট প্যাটেল

38

আপনার যখন ইতিমধ্যে সমস্ত "টুকরা" যুক্ত হতে চান তবে এগুলি ব্যবহার StringBuilderকরার কোনও মানে হয় না no ব্যবহার StringBuilder এবং আপনার নমুনা কোড অনুযায়ী একই কলে স্ট্রিং সংযুক্তকরণের এমনকি খারাপ।

এটি আরও ভাল হবে:

return "select id1, " + " id2 " + " from " + " table";

এই ক্ষেত্রে, স্ট্রিং কনটেনটেশনটি আসলে যেকোনভাবে সংকলন সময়ে ঘটছে , সুতরাং এটি সমান-সরল সমান:

return "select id1, id2 from table";

ব্যবহার new StringBuilder().append("select id1, ").append(" id2 ")....toString()প্রকৃতপক্ষে এই ক্ষেত্রে পারফরম্যান্সকে বাধাগ্রস্ত করবে , কারণ এটি সংকলনের সময় পরিবর্তে মৃত্যুদন্ড কার্যকর করার সময় সংক্ষেপণকে বাধ্য করে । উফ!

যদি আসল কোডটি কোয়েরিতে মানগুলি অন্তর্ভুক্ত করে একটি এসকিউএল কোয়েরি তৈরি করে , তবে এটি অন্য একটি পৃথক সমস্যা, এটি হ'ল আপনাকে প্যারামিটারাইজড কোয়েরিগুলি ব্যবহার করা উচিত, এসকিউএল এর পরিবর্তে প্যারামিটারগুলিতে মানগুলি নির্দিষ্ট করে।

আমার একটি নিবন্ধ আছে String/StringBuffer যা আমি কিছুক্ষণ আগে লিখেছিলাম - আগে StringBuilderআসার আগে । নীতিগুলি StringBuilderএকইভাবে প্রয়োগ হয় যদিও।


10

[[এখানে কিছু ভাল উত্তর রয়েছে তবে আমি দেখতে পাচ্ছি যে তাদের এখনও কিছুটা তথ্যের অভাব রয়েছে। ]]

return (new StringBuilder("select id1, " + " id2 " + " from " + " table"))
     .toString();

সুতরাং আপনি যেমন উল্লেখ করেছেন, আপনি যে উদাহরণটি দিয়েছেন তা সরলবাদী তবে আসুন যাইহোক এটি বিশ্লেষণ করুন। এখানে যা ঘটে তা সংকলক আসলে +এখানে কাজ করে কারণ "select id1, " + " id2 " + " from " + " table"সমস্ত ধ্রুবক। সুতরাং এটি পরিণত হয়:

return new StringBuilder("select id1,  id2  from  table").toString();

এই ক্ষেত্রে, স্পষ্টতই, ব্যবহার করার কোনও মানে নেই StringBuilder। আপনি পাশাপাশি করতে পারেন:

// the compiler combines these constant strings
return "select id1, " + " id2 " + " from " + " table";

তবে, আপনি যদি কোনও ক্ষেত্র বা অন্যান্য অ-স্থির সংযোজন করছিলেন তবুও সংকলকটি অভ্যন্তরীণ ব্যবহার করবে StringBuilder- আপনার কোনও সংজ্ঞা দেওয়ার দরকার নেই:

// an internal StringBuilder is used here
return "select id1, " + fieldName + " from " + tableName;

কভারগুলির নীচে, এটি এমন কোডে পরিণত হয় যা প্রায় সমান:

StringBuilder sb = new StringBuilder("select id1, ");
sb.append(fieldName).append(" from ").append(tableName);
return sb.toString();

আপনার কেবলমাত্র শর্তযুক্ত কোড থাকলেই কেবল আপনাকে StringBuilder সরাসরি ব্যবহারের প্রয়োজন হয় । উদাহরণস্বরূপ, নীচের মতো দেখতে কোডটি একটির জন্য মরিয়া StringBuilder:

// 1 StringBuilder used in this line
String query = "select id1, " + fieldName + " from " + tableName;
if (where != null) {
   // another StringBuilder used here
   query += ' ' + where;
}

+প্রথম লাইনে একটি ব্যবহার StringBuilderউদাহরণস্বরূপ। তারপরে +=ব্যবহারগুলি অন্য একটি StringBuilderউদাহরণ ব্যবহার করে । এটি করা আরও দক্ষ:

// choose a good starting size to lower chances of reallocation
StringBuilder sb = new StringBuilder(64);
sb.append("select id1, ").append(fieldName).append(" from ").append(tableName);
// conditional code
if (where != null) {
   sb.append(' ').append(where);
}
return sb.toString();

আমি StringBuilderযখন ব্যবহার করি অন্য সময়টি যখন আমি প্রচুর পদ্ধতি কল থেকে স্ট্রিং তৈরি করি। তারপরে আমি এমন পদ্ধতি তৈরি করতে পারি যা একটি StringBuilderযুক্তি গ্রহণ করে:

private void addWhere(StringBuilder sb) {
   if (where != null) {
      sb.append(' ').append(where);
   }
}

আপনি যখন একটি ব্যবহার করছেন StringBuilder, আপনার +একই সময়ে যে কোনও ব্যবহারের জন্য নজর রাখা উচিত :

sb.append("select " + fieldName);

এটি +অন্য একটি অভ্যন্তরীণ StringBuilderতৈরি করার কারণ ঘটবে । এটি অবশ্যই হওয়া উচিত:

sb.append("select ").append(fieldName);

অবশেষে, @ টিজ্রোডার হিসাবে উল্লেখ করা হয়েছে, আপনার সর্বদা এর আকারের উপর অনুমান করা উচিত StringBuilder। এটি char[]অভ্যন্তরীণ বাফারের আকার বাড়ানোর সময় তৈরি করা সামগ্রীর সংখ্যা বাঁচাবে ।


4

আপনি অনুমান করে সঠিক যে স্ট্রিং বিল্ডার ব্যবহারের লক্ষ্য অর্জন করা হয়নি, কমপক্ষে তার সম্পূর্ণ পরিমাণে নয়।

যাইহোক, যখন "select id1, " + " id2 " + " from " + " table"সংকলকটি এক্সপ্রেশনটি দেখে এটি কোডটি নির্গত করে যা প্রকৃতপক্ষে একটি StringBuilderপর্দার আড়ালে তৈরি করে এবং এতে সংযোজন করে, সুতরাং শেষ ফলাফলটি এতদূর খারাপ হয় না।

তবে অবশ্যই যে কেউ কোডটি দেখছেন তা ভাবতে বাধ্য যে এটি এক ধরণের প্রতিবন্ধী।


2

আপনি যে কোড পোস্ট করেছেন তাতে কোনও সুবিধা থাকবে না, কারণ আপনি স্ট্রিংবিল্ডারের অপব্যবহার করছেন। আপনি উভয় ক্ষেত্রে একই স্ট্রিং তৈরি করেন। স্ট্রিংবিল্ডার +ব্যবহার করে আপনি appendপদ্ধতিটি ব্যবহার করে স্ট্রিংয়ের অপারেশন এড়াতে পারবেন । আপনার এটি এইভাবে ব্যবহার করা উচিত:

return new StringBuilder("select id1, ").append(" id2 ").append(" from ").append(" table").toString();

জাভাতে, স্ট্রিং টাইপটি অক্ষরের একটি অবিচ্ছেদ্য অনুক্রম, সুতরাং আপনি যখন দুটি স্ট্রিং যুক্ত করেন তখন ভিএম একটি নতুন স্ট্রিং মান উভয় অপারেন্ডকে একত্রিত করে তৈরি করে।

স্ট্রিংবিল্ডার অক্ষরের একটি পরিবর্তনীয় ক্রম সরবরাহ করে, যা আপনি নতুন স্ট্রিং অবজেক্ট তৈরি না করে বিভিন্ন মান বা ভেরিয়েবলকে একত্রিত করতে ব্যবহার করতে পারেন এবং তাই এটি স্ট্রিংয়ের সাথে কাজ করার চেয়ে কখনও কখনও আরও কার্যকর হতে পারে can

এটি কিছু কার্যকর বৈশিষ্ট্য সরবরাহ করে, অন্য পদ্ধতির মধ্যে প্যারামিটার হিসাবে পাস করা চর ক্রমের সামগ্রী পরিবর্তন করার সাথে, যা আপনি স্ট্রিংগুলির সাথে করতে পারবেন না।

private void addWhereClause(StringBuilder sql, String column, String value) {
   //WARNING: only as an example, never append directly a value to a SQL String, or you'll be exposed to SQL Injection
   sql.append(" where ").append(column).append(" = ").append(value);
}

Http://docs.oracle.com/javase/tutorial/java/data/buffers.html এ আরও তথ্য


4
না, আপনার করা উচিত নয়। এটি ব্যবহার করার চেয়ে কম পঠনযোগ্য +, যা যাইহোক একই কোডে রূপান্তরিত হবে। StringBuilderআপনি যখন একক অভিব্যক্তিতে সমস্ত উপসংহার সম্পাদন করতে পারবেন না তখন কার্যকর হয় তবে এই ক্ষেত্রে নয়।
জন স্কিটি

4
আমি বুঝতে পারি যে প্রশ্নের স্ট্রিং একটি উদাহরণ হিসাবে পোস্ট করা হয়েছে। স্ট্রিংবিল্ডারকে না দিয়ে আলাদা আলাদা টুকরো যুক্ত করার মতো এটি "স্থির" স্ট্রিং তৈরি করার কোনও অর্থ নেই, কারণ আপনি কেবল এটি একটিমাত্র ধ্রুবক "টেবিল থেকে আইডি 1, আইডি 2 নির্বাচন করুন"
টমাস ন্যারোস

তবে যদি ভেরিয়েবলগুলি থেকে অ-ধ্রুবক মানগুলি পাওয়া যায় StringBuilderতবে আপনি যদি ব্যবহার করতে চান তবে এটি একটি একক ব্যবহার করবে return "select id1, " + foo + "something else" + bar;- তবে কেন এটি করবেন না? প্রশ্নটি কোনও ইঙ্গিত দেয় না যে কোনও কিছুকে StringBuilderপ্রায় কাছাকাছি যেতে হবে।
জন স্কিটি

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.