Эффективная замена Java String - PullRequest
1 голос
/ 29 апреля 2011

У нас есть следующий код:

String templateQuery = "select * from my_table where col1=$1 or col2 like '%$2.$1'";
String tmp = templateQuery;

for(int i=1;i<=maxCols;i++) {
    tmp = tmp.replaceAll("\\$"+i, data[i-1]);
}

Этот код работает нормально, так как maxCols никогда не превышает 10. Но мой коллега не согласен со мной, заявив, что этот код занимает слишком много памяти. Можете ли вы помочь нам?

EDIT : Я изменил исходный шаблонQuery с гораздо более реалистичным. Во-вторых, templateQuery потенциально может быть большой строкой.

РЕДАКТИРОВАТЬ 2 : Спасибо тем, кто указал на проблему SQLInjection .

Ответы [ 5 ]

6 голосов
/ 29 апреля 2011

Не делай этого.

Не по соображениям производительности (которые будут незначительными по сравнению со стоимостью запроса к базе данных), но во избежание атак с использованием SQL-инъекций. Что произойдет, если data[0] на самом деле строка

' OR 'x' = 'x

Тогда вы получите SQL-выражение:

SELECT * FROM my_table WHERE col1='' OR 'x' = 'x'

Я думаю, что мы можем согласиться, это не то, что вы хотели.

Вместо этого используйте параметризованный оператор SQL (PreparedStatement) и заставьте драйвер базы данных отправлять значения параметров отдельно.

РЕДАКТИРОВАТЬ: В других комментариях OP указал, что строка шаблона может быть довольно длинной, и некоторые параметры могут фактически включать несколько начальных значений, объединенных вместе. Я все еще говорю, что стоимость замены, вероятно, будет незначительной в великой схеме вещей, и я все еще говорю, что PreparedStatement - это путь. Вы должны выполнить любые операции объединения, которые вам нужны для ввода, прежде чем устанавливать их в качестве значений для PreparedStatement - поэтому шаблону может понадобиться SQL с заполнителями SQL, а затем «подшаблоны», чтобы выяснить, как перейти от вашего ввода к параметры для PreparedStatement. Что бы вы ни делали, ввод значений непосредственно в SQL - неправильный подход.

3 голосов
/ 29 апреля 2011

Почему вы просто не используете PreparedStatement с параметрами замены?

String templateQuery = "SELECT * FROM my_table WHERE col1 = ?";
PreparedStatement ps = con.prepareStatement(templateQuery);
for (int i = 0; i < data.length; i++) {
    ps.setString(i + 1, data[i]);
}
ResultSet rs = ps.executeQuery();

В противном случае вы уязвимы для SQL-инъекции , если вы используете замену строки, как у вас.

3 голосов
/ 29 апреля 2011

Он правильный, потому что вы создаете maxCols tmp Strings .Я понял, что это для команд Sql, если это так, почему вы не используете PreparedStatement (http://download.oracle.com/javase/1.4.2/docs/api/java/sql/PreparedStatement.html) для этой задачи?

Кроме того, для форматирования строк, а не использовать замену,используйте Formatter , это намного элегантнее: http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html

0 голосов
/ 29 апреля 2011

Является ли это потребляет слишком много памяти, открыто для обсуждения (что такое "слишком много"?)

Тем не менее, для такого рода вещей вы должны использовать PreparedStatement. Это позволяет вам делать в точности то, что вы пытаетесь достичь, но гораздо чище.

0 голосов
/ 29 апреля 2011

Ваш коллега прав в том, что каждая замена строки создает новую копию строки. (Однако их стоимость, вероятно, незначительна при менее чем 10 параметрах.) Более того, для каждого выполнения этого запроса механизм SQL должен анализировать его заново, что каждый раз потребляет гораздо больше дополнительных ресурсов.

Потенциально большая проблема заключается в том, что код подозревается к SQL-инъекции . Если входные данные поступают из внешнего источника, хакер может передать параметр, такой как "col1; drop table my_table;", эффективно удаляя всю таблицу.

Все это можно решить, используя вместо этого PreparedStatement.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...