Когда мы должны использовать PreparedStatement вместо Statement? - PullRequest
26 голосов
/ 20 января 2010

Я знаю преимущества использования PreparedStatement, которые

  • запрос переписывается и компилируется сервером базы данных
  • защита от внедрения SQL

Но я хочу знать, когда мы используем его вместо Statement?

Ответы [ 7 ]

27 голосов
/ 20 января 2010
  1. Запрос переписывается и компилируется сервером базы данных

    Если вы не используете подготовленный оператор, серверу базы данных придется проанализировать и вычислитьплан выполнения оператора каждый раз, когда вы запускаете его.Если вы обнаружите, что один и тот же оператор будет выполняться несколько раз (с разными параметрами), то стоит подготовить оператор один раз и повторно использовать этот подготовленный оператор.Если вы запрашиваете базу данных adhoc, то, вероятно, это мало что даст.

  2. Защищено от внедрения SQL

    Это преимущество, которое вы почтивсегда хочу, следовательно, вескую причину использовать PreparedStatement каждый раз.Это является следствием необходимости параметризации запроса, но делает его выполнение намного безопаснее.Единственный раз, когда я могу подумать, что это было бы бесполезно, это если бы вы разрешали запросы к базе данных adhoc;Вы можете просто использовать объект Statement, если вы создавали прототип приложения и выполняли его быстрее для вас, или если запрос не содержит параметров.

17 голосов
/ 20 января 2010

Спросите Тома мнение :

Использование оператора в JDBC должно быть на 100% локализовано для использования для DDL (ALTER, CREATE, GRANT и т. Д.), Поскольку это единственные типы операторов, которые не могут принимать BIND ПЕРЕМЕННЫЕ.

PreparedStatements или CallableStatements следует использовать для КАЖДОГО ДРУГОГО типа операторов (DML, Запросы). Так как это типы операторов, которые принимают переменные связывания.

Это факт, правило, закон - используйте готовые высказывания ВЕЗДЕ. Используйте ЗАЯВЛЕНИЯ почти не где.

Он специально говорит об Oracle, но тот же принцип применим к любой базе данных, которая кэширует планы выполнения.

Приложения баз данных, которые одновременно масштабируют и предотвращают атаки с использованием SQL-инъекций? Какой минус?

9 голосов
/ 20 января 2010

Я бы перевернул этот раунд: в общедоступном приложении вы, как правило, должны всегда использовать подготовленные операторы , если у вас нет действительно веской причины не , и вы всегда должны предоставлять параметры«правильно» к подготовленному выражению, а не путем сращивания их в строку запроса.

Почему?Ну, в основном по причинам, которые вы назвали (или, по крайней мере, по второй) ...

5 голосов
/ 22 ноября 2011

PreparedStatements следует использовать очень осторожно в предложениях WHERE.

Предположим, что таблица определена как:

create table t (int o, k varchar(100), v varchar(100))

(например, "o: идентификатор объекта (внешний ключ), k: ключ-атрибут, v: значение-атрибут").

Кроме того, существует (неуникальный) индекс для v.

create index ixt on t ( v )

Предположим, что эта таблица содержит 200 миллионов строк, вставленных как:

for (i = 0; i < 100*1000*1000; i++) {
  insert into t (o,k,v) values (i,'k1','v1');
  insert into t (o,k,v) values (i,'k2', Convert(i, varchar));
}

(«Таким образом, каждый объект o имеет атрибуты k1 = v1 и k2 = o»)

Тогда вы не должны строить запросы вроде:

select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k=? and tx.v=? and ty.k=? and ty.v=?

("найти объекты, которые имеют два заданных атрибута")

Мой опыт работы с ORACLE и MSSQL заключается в том, что для выполнения этих запросов может потребоваться много минут . Это верно, даже если ни одна строка не соответствует предложению where. Это зависит от того, решит ли SQL-сервер сначала поискать tx.v или ty.v.

Один шок вставляет значения для столбцов k и v непосредственно в оператор. Я думаю, это потому, что SQL-серверы учитывают значения при расчете плана выполнения.

Запрос, который выглядит так, всегда возвращается через миллисекунды:

select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k='k1' and tx.v='v1' and ty.k='k2' and ty.v='1234'

("SQL-сервер всегда будет сначала искать v = '1234', а затем v = 'v1'")

Привет
Wolfgang

1 голос
/ 11 октября 2016

Вы всегда можете использовать PreparedStatement вместо Statment (выбрать, вставить, обновить, удалить).Повышение производительности и защита от внедрения SQL.

Но не используйте его с динамическим запросом, таким как запрос с WHERE variable IN [ hundreds possibilities ]:

  1. Это непродуктивно,вы потеряли производительность и память, потому что вы кешируете каждый раз новый запрос, а PreparedStatement не только для SQL-инъекций, но и для производительности.В этом случае оператор не будет медленнее.

  2. Ваш пул имеет ограничение PreparedStatment (-1 по умолчанию, но вы должны его ограничить), и вы достигнете этого предела!и если у вас нет предела или очень большой предел, у вас есть некоторый риск утечки памяти, а в крайнем случае ошибки OutofMemory.Так что, если это для вашего маленького личного проекта, используемого 3 пользователями, это не драматично, но вы не хотите этого, если вы в большой компании и ваше приложение используют тысячи людей и миллион запросов.

Немного читаю. IBM: периодические ошибки OutOfMemory с подготовленным кэшированием операторов

1 голос
/ 28 ноября 2015

Оператор : Каждый раз, когда выполняется запрос SQL, этот оператор SQL отправляется в СУБД, где он компилируется. Таким образом, это увеличивает нагрузку на сервер и снижает производительность.

connection con=null; 
  String sql="select * from employee where id=5";
Statement st=conn.createStatement();

PreparedStatement : в отличие от оператора PreparedStatement предоставляется SQL-запрос в качестве параметра при его создании.

connection con=null; 
String sql="select * from employee where id=?";
PreparedStatement ps=conn.prepareStatement(sql);

Этот оператор sql отправляется в базу данных, где он компилируется. Таким образом, в readyStatement скомпилированное происходит только один раз, но в скомпилированном выражении происходит каждый раз, когда вызывается Statement.

0 голосов
/ 20 января 2010

Помимо предотвращения внедрения SQL-кода, переносимости форматирования (которую вы не можете получить из Statement), производительность является очевидной причиной. Тем не менее, PreparedStatement не приходит без каких-либо штрафов. Например, обычно он медленнее, чем Statement, если выполняется только один раз, так как есть некоторые издержки. Таким образом, общая идея PreparedStatement должна использоваться, когда вы выполняете один и тот же запрос много раз. Однако, сколько накладных расходов зависит от конкретной реализации сервера базы данных, поэтому, когда выбор PreparedStatement вместо Statement, исходя из соображений производительности, должен действительно зависеть от вашего реального опыта / экспериментов с конкретным сервером базы данных.

...