在SQL中使用StringBuilder的正确方法

在SQL中使用StringBuilder的正确方法

本文介绍了在SQL中使用StringBuilder的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚在我的项目中发现了一些这样的SQL查询构建:

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

这个 StringBuilder 是否实现了它的目标,即减少内存使用量?



我对此表示怀疑,因为在构造函数中使用了'+'(String concat运算符)。这会占用与使用String相同的内存量,如下面的代码吗?我明白了,它在使用 StringBuilder.append()时有所不同。

 返回select id1,+id2+from+table; 

两个语句的内存使用量是否相等?请澄清。



提前致谢!



编辑:



BTW,这不是我的代码。在一个旧项目中找到它。此外,查询不是我的示例中的查询。 :)

解决方案

不,完全没有。该代码未正确使用 StringBuilder 。 (我认为你错误引用了它;肯定没有 id2 的引用?)



请注意,目标(通常)是减少内存 churn 而不是使用的总内存,以使垃圾收集器的生活更轻松。

不,它会导致更多内存流失,而不仅仅是你所引用的直接连续。 (直到/除非JVM优化器发现代码中的显式 StringBuilder 是不必要的并且优化它,如果可以的话。)



如果该代码的作者想要使用 StringBuilder (有参数,但也有反对;参见本答案末尾的注释),最好是做得恰当(这里我假设实际上没有 id2 ):

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

请注意,我已列出 some_appropriate_size in StringBuilder 构造函数,因此它开始时有足够的容量来容纳我们要追加的完整内容。如果您未指定,则使用的默认大小为,通常太小,导致 StringBuilder 不得不重新分配以使自己更大(IIRC,在Sun / Oracle JDK中,它加倍本身[或更多,如果它知道它需要更多来满足特定的追加]每次它用完房间时。)



如果使用Sun / Oracle编译器编译,您可能听说字符串连接使用 StringBuilder 。这是事实,它将使用一个 StringBuilder 作为整体表达式。但它将使用默认构造函数,这意味着在大多数情况下,它将不得不进行重新分配。不过,它更容易阅读。请注意,这是系列连接的 true。因此,例如,这使用一个 StringBuilder

 返回前缀 + variable1 +middle+ variable2 +end; 

它大致转换为:

  StringBuilder tmp = new StringBuilder(); //使用默认的16个字符大小
tmp.append(prefix);
tmp.append(variable1);
tmp.append(middle);
tmp.append(variable2);
tmp.append(end);
返回tmp.toString();

所以没关系,虽然默认构造函数和后续重新分配不理想,但赔率很高它是否足够好 —串联是 lot 更具可读性。



但这仅适用于单个表达式。多个 StringBuilder 用于此:

  String s; 
s =前缀;
s + = variable1;
s + =中间;
s + = variable2;
s + =结束;
返回s;

最终会变成这样:

  String s; 
StringBuilder tmp;
s =前缀;
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();
返回s;

......这非常难看。



无关紧要并且具有可读性(增强可维护性)是首选,除非出现特定的性能问题。


I just found some sql query build like this in my project:

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

Does this StringBuilder achieve its aim, i.e reducing memory usage?

I doubt that, because in the constructor the '+' (String concat operator) is used. Will that take the same amount of memory as using String like the code below? s I understood, it differs when using StringBuilder.append().

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

Are both statements equal in memory usage or not? Please clarify.

Thanks in advance!

Edit:

BTW, it is not my code. Found it in an old project. Also, the query is not so small as the one in my example. :)

解决方案

No, not at all. That code is not using StringBuilder correctly. (I think you've misquoted it, though; surely there aren't quotes around id2 and table?)

Note that the aim (usually) is to reduce memory churn rather than total memory used, to make life a bit easier on the garbage collector.

No, it'll cause more memory churn than just the straight concat you quoted. (Until/unless the JVM optimizer sees that the explicit StringBuilder in the code is unnecessary and optimizes it out, if it can.)

If the author of that code wants to use StringBuilder (there are arguments for, but also against; see note at the end of this answer), better to do it properly (here I'm assuming there aren't actually quotes around id2 and table):

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

Note that I've listed some_appropriate_size in the StringBuilder constructor, so that it starts out with enough capacity for the full content we're going to append. The default size used if you don't specify one is 16 characters, which is usually too small and results in the StringBuilder having to do reallocations to make itself bigger (IIRC, in the Sun/Oracle JDK, it doubles itself [or more, if it knows it needs more to satisfy a specific append] each time it runs out of room).

You may have heard that string concatenation will use a StringBuilder under the covers if compiled with the Sun/Oracle compiler. This is true, it will use one StringBuilder for the overall expression. But it will use the default constructor, which means in the majority of cases, it will have to do a reallocation. It's easier to read, though. Note that this is not true of a series of concatenations. So for instance, this uses one StringBuilder:

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

It roughly translates to:

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();

So that's okay, although the default constructor and subsequent reallocation(s) isn't ideal, the odds are it's good enough — and the concatenation is a lot more readable.

But that's only for a single expression. Multiple StringBuilders are used for this:

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

That ends up becoming something like this:

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;

...which is pretty ugly.

It's important to remember, though, that in all but a very few cases it doesn't matter and going with readability (which enhances maintainability) is preferred barring a specific performance issue.

这篇关于在SQL中使用StringBuilder的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 08:06