SQL에서 StringBuilder를 사용하는 올바른 방법
내 프로젝트에서 다음과 같은 SQL 쿼리 빌드를 찾았습니다.
return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString();
이것이 StringBuilder
목표를 달성 합니까 , 즉 메모리 사용량을 줄입니까?
생성자에서 '+'(문자열 연결 연산자)가 사용되기 때문에 의심합니다. 아래 코드와 같이 String을 사용하는 것과 같은 양의 메모리를 사용합니까? s를 사용할 때 다릅니다 StringBuilder.append()
.
return "select id1, " + " id2 " + " from " + " table";
두 문장 모두 메모리 사용량이 같습니까? 명확히하십시오.
미리 감사드립니다!
편집하다:
BTW, 내 코드가 아닙니다 . 오래된 프로젝트에서 찾았습니다. 또한 쿼리는 내 예제의 쿼리만큼 작지 않습니다. :)
StringBuilder를 사용하는 목적, 즉 메모리 감소. 달성 되었습니까?
아니, 전혀. 해당 코드가 StringBuilder
올바르게 사용되지 않습니다 . (나는 당신이 그것을 잘못 인용하지만 것 같은데, 확실히이 따옴표없는 id2
및 table
?)
목표는 (일반적으로) 사용 된 총 메모리가 아닌 메모리 변동 을 줄여 가비지 수집기의 삶을 조금 더 쉽게 만드는 것입니다.
아래와 같이 String을 사용하는 것과 동일한 메모리가 필요합니까?
아니요, 인용 한 직선 연결보다 더 많은 메모리 변동을 일으킬 것입니다. (JVM 옵티마이 저가 StringBuilder
코드 의 명시 적 코드가 불필요하다고 판단하고 가능한 경우이를 최적화하지 않는 한 )
해당 코드의 작성자가 StringBuilder
(에 대한 논쟁이 있지만 반대도 있습니다.이 답변의 끝 부분에있는 참고 사항 참조) 올바르게 수행하는 것이 좋습니다 (실제로 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();
내가 열거 한 것을 참고 some_appropriate_size
에 StringBuilder
우리가 추가 할거야 전체 내용에 대한 충분한 용량로 시작 그래서, 생성자입니다. 하나를 지정하지 않은 경우 사용되는 기본 크기는 16 자 입니다. 일반적으로 너무 작아서 StringBuilder
자신을 더 크게 만들기 위해 재 할당을해야합니다 (IIRC, Sun / Oracle JDK에서는 두 배가됩니다. 공간이 부족할 때 append
마다 특정 ] 을 만족시키기 위해 더 많은 것이 필요하다는 것을 알고 있습니다 .)
Sun / Oracle 컴파일러로 컴파일 한 경우 문자열 연결 이 내부적으로 a 를 사용 한다고 들었을 것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
s가 사용됩니다.
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.
When you already have all the "pieces" you wish to append, there is no point in using StringBuilder
at all. Using StringBuilder
and string concatenation in the same call as per your sample code is even worse.
This would be better:
return "select id1, " + " id2 " + " from " + " table";
In this case, the string concatenation is actually happening at compile-time anyway, so it's equivalent to the even-simpler:
return "select id1, id2 from table";
Using new StringBuilder().append("select id1, ").append(" id2 ")....toString()
will actually hinder performance in this case, because it forces the concatenation to be performed at execution time, instead of at compile time. Oops.
If the real code is building a SQL query by including values in the query, then that's another separate issue, which is that you should be using parameterized queries, specifying the values in the parameters rather than in the SQL.
I have an article on String
/ StringBuffer
which I wrote a while ago - before StringBuilder
came along. The principles apply to StringBuilder
in the same way though.
[[ There are some good answers here but I find that they still are lacking a bit of information. ]]
return (new StringBuilder("select id1, " + " id2 " + " from " + " table"))
.toString();
So as you point out, the example you give is a simplistic but let's analyze it anyway. What happens here is the compiler actually does the +
work here because "select id1, " + " id2 " + " from " + " table"
are all constants. So this turns into:
return new StringBuilder("select id1, id2 from table").toString();
In this case, obviously, there is no point in using StringBuilder
. You might as well do:
// the compiler combines these constant strings
return "select id1, " + " id2 " + " from " + " table";
However, even if you were appending any fields or other non-constants then the compiler would use an internal StringBuilder
-- there's no need for you to define one:
// an internal StringBuilder is used here
return "select id1, " + fieldName + " from " + tableName;
Under the covers, this turns into code that is approximately equivalent to:
StringBuilder sb = new StringBuilder("select id1, ");
sb.append(fieldName).append(" from ").append(tableName);
return sb.toString();
Really the only time you need to use StringBuilder
directly is when you have conditional code. For example, code that looks like the following is desperate for a StringBuilder
:
// 1 StringBuilder used in this line
String query = "select id1, " + fieldName + " from " + tableName;
if (where != null) {
// another StringBuilder used here
query += ' ' + where;
}
The +
in the first line uses one StringBuilder
instance. Then the +=
uses another StringBuilder
instance. It is more efficient to do:
// 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();
Another time that I use a StringBuilder
is when I'm building a string from a number of method calls. Then I can create methods that take a StringBuilder
argument:
private void addWhere(StringBuilder sb) {
if (where != null) {
sb.append(' ').append(where);
}
}
When you are using a StringBuilder
, you should watch for any usage of +
at the same time:
sb.append("select " + fieldName);
That +
will cause another internal StringBuilder
to be created. This should of course be:
sb.append("select ").append(fieldName);
Lastly, as @T.J.rowder points out, you should always make a guess at the size of the StringBuilder
. This will save on the number of char[]
objects created when growing the size of the internal buffer.
You are correct in guessing that the aim of using string builder is not achieved, at least not to its full extent.
However, when the compiler sees the expression "select id1, " + " id2 " + " from " + " table"
it emits code which actually creates a StringBuilder
behind the scenes and appends to it, so the end result is not that bad afterall.
But of course anyone looking at that code is bound to think that it is kind of retarded.
In the code you have posted there would be no advantages, as you are misusing the StringBuilder. You build the same String in both cases. Using StringBuilder you can avoid the +
operation on Strings using the append
method. You should use it this way:
return new StringBuilder("select id1, ").append(" id2 ").append(" from ").append(" table").toString();
In Java, the String type is an inmutable sequence of characters, so when you add two Strings the VM creates a new String value with both operands concatenated.
StringBuilder provides a mutable sequence of characters, which you can use to concat different values or variables without creating new String objects, and so it can sometimes be more efficient than working with strings
This provides some useful features, as changing the content of a char sequence passed as parameter inside another method, which you can't do with Strings.
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);
}
More info at http://docs.oracle.com/javase/tutorial/java/data/buffers.html
You could also use MessageFormat too
참고URL : https://stackoverflow.com/questions/8725739/correct-way-to-use-stringbuilder-in-sql
'IT story' 카테고리의 다른 글
Java 로깅 API를 사용하는 동안 기본 콘솔 핸들러를 비활성화하려면 어떻게해야합니까? (0) | 2020.09.08 |
---|---|
비활성화 된 입력 필드의 값 제출 (0) | 2020.09.08 |
ASP.NET Web Api : 요청 된 리소스가 http 메서드 'GET'을 지원하지 않습니다. (0) | 2020.09.08 |
Django 클래스 기반보기 : as_view 메소드에 추가 매개 변수를 어떻게 전달합니까? (0) | 2020.09.08 |
BOM으로 UTF-8 파일을 검색하는 우아한 방법? (0) | 2020.09.08 |