Разница между выражением и подготовленным соглашением

Подготовленное выражение представляет собой несколько более мощную версию Statement и всегда должно быть как минимум быстрым и легким в обращении как выражение. Подготовленное выражение может быть параметризованным

Большинство реляционных баз данных обрабатывает запрос JDBC/SQL в четыре этапа:

  • Разбор входящего запроса SQL
  • Скомпилировать SQL-запрос
  • Планирование/оптимизация пути сбора данных
  • Выполнять оптимизированные запросы/приобретать и возвращать данные

Заявление всегда будет проходить через четыре шага выше для каждого SQL-запроса, отправленного в базу данных. Подготовленный отчет предварительно выполняет шаги (1) - (3) в процессе выполнения выше. Таким образом, при создании Подготовленного заявления некоторая предварительная оптимизация выполняется немедленно. Эффект заключается в уменьшении нагрузки на механизм базы данных во время выполнения.

Теперь мой вопрос в том, что "есть ли другое преимущество использования подготовленного заявления?"

Ответ 1

Преимущества PreparedStatement:

  • Предварительная компиляция и кэширование базы данных SQL-оператора приводит к более быстрому выполнению и возможности повторного использования одного и того же оператора SQL в партиях.

  • Автоматическая защита SQL-инъекция атаки путем встроенного экранирования кавычек и других специальных символов. Обратите внимание, что для этого необходимо использовать любой из методов PreparedStatement setXxx() для установки значений

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    preparedStatement.setString(1, person.getName());
    preparedStatement.setString(2, person.getEmail());
    preparedStatement.setTimestamp(3, new Timestamp(person.getBirthdate().getTime()));
    preparedStatement.setBinaryStream(4, person.getPhoto());
    preparedStatement.executeUpdate();
    

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

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'");
    preparedStatement.executeUpdate();
    
  • Облегчает настройку нестандартных объектов Java в строке SQL, например. Date, Time, Timestamp, BigDecimal, InputStream (Blob) и Reader (Clob). На большинстве этих типов вы не можете "просто" сделать toString(), как это было бы в простой Statement. Вы даже можете реорганизовать все это, используя PreparedStatement#setObject() внутри цикла, как показано в нижеприведенном методе утилиты:

    public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
        for (int i = 0; i < values.length; i++) {
            preparedStatement.setObject(i + 1, values[i]);
        }
    }
    

    Что можно использовать, как показано ниже:

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    setValues(preparedStatement, person.getName(), person.getEmail(), new Timestamp(person.getBirthdate().getTime()), person.getPhoto());
    preparedStatement.executeUpdate();
    

Ответ 2

  • Они предварительно скомпилированы (один раз), поэтому быстрее для повторного выполнения динамического SQL (где изменяются параметры)

  • Кэширование операторов базы данных повышает производительность выполнения БД

    Базы данных хранят кеши планов выполнения для ранее выполненных операторов. Это позволяет механизму базы данных повторно использовать планы для операторов, которые были выполнены ранее. Поскольку PreparedStatement использует параметры, каждый раз, когда он выполняется, он отображается как один и тот же SQL, база данных может повторно использовать предыдущий план доступа, сокращая обработку. Выражения "встраивают" параметры в строку SQL и поэтому не отображаются как один и тот же SQL для БД, предотвращая использование кеша.

  • Протокол двоичной связи означает меньшую пропускную способность и более быстрое общение с сервером БД

    Подготовленные операторы обычно выполняются с помощью двоичного протокола, отличного от SQL. Это означает, что в пакетах меньше данных, поэтому связь с сервером выполняется быстрее. Как правило, сетевые операции на порядок быстрее, чем операции с дисками, которые на порядок выше, чем у процессоров памяти в памяти. Следовательно, любое снижение объема данных, передаваемых по сети, будет иметь хорошее влияние на общую производительность.

  • Они защищают от SQL-инъекции, избегая текста для всех предоставленных параметров.

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

  • В java можно вызвать getMetadata() и getParameterMetadata() для отражения полей результатов и полей параметров, соответственно

  • В java интеллектуально принимает java-объекты как типы параметров через setObject, setBoolean, setByte, setDate, setDouble, setDouble, setFloat, setInt, setLong, setShort, setTime, setTimestamp - он преобразуется в формат типа JDBC, который является понятным для DB (а не только для формата toString()).

  • В java, принимает SQL ARRAY, как тип параметра с помощью метода setArray

  • В java принимает CLOB, BLOB, OutputStreams и Readers в качестве параметра "feeds" через методы setClob/setNClob, setBlob, setBinaryStream, setCharacterStream/setAsciiStream/setNCharacterStream, соответственно

  • В java задаются значения, специфичные для БД, для SQL DATALINK, SQL ROWID, SQL XML и NULL через setURL, setRowId, setSQLXML и setNull методы

  • В java наследует все методы из Statement. Он наследует метод addBatch и дополнительно позволяет добавлять набор значений параметров для соответствия набору пакетных SQL-команд с помощью метода addBatch.

  • В java специальный тип PreparedStatement (подкласса CallableStatement) позволяет выполнять хранимые процедуры, поддерживая высокую производительность, инкапсуляцию, процедурное программирование и SQL, администрирование БД/обслуживание/настройку логики и использование проприетарных Логика и функции БД

Ответ 3

PreparedStatement - очень хорошая защита (но не надежная защита) в предотвращении атак SQL-инъекций. Значения параметров привязки - хороший способ защитить от "маленькие Bobby Tables" , сделав нежелательный визит.

Ответ 4

Некоторые из преимуществ PreparedStatement over Statement:

  • PreparedStatement помогает нам предотвращать атаки SQL-инъекций, поскольку он автоматически ускользает от специальных символов.
  • PreparedStatement позволяет выполнять динамические запросы с вводом параметров.
  • PreparedStatement предоставляет различные типы методов setter для установки входных параметров для запроса.
  • PreparedStatement быстрее, чем Statement. Он становится более заметным, когда мы повторно используем PreparedStatement или используем его методы пакетной обработки для выполнения нескольких запросов.
  • PreparedStatement помогает нам в написании объектно-ориентированного кода с помощью методов setter, тогда как с Statement мы должны использовать String Concatenation для создания запроса. Если задано несколько параметров, запись Query с помощью String конкатенации выглядит очень уродливой и подверженной ошибкам.

Подробнее о проблеме впрыска SQL на http://www.journaldev.com/2489/jdbc-statement-vs-preparedstatement-sql-injection-example

Ответ 5

нечего добавить,

1 - если вы хотите выполнить запрос в цикле (более одного раза), подготовленный оператор может быть быстрее, из-за оптимизации, о которой вы говорили.

2 - параметризованный запрос - хороший способ избежать SQL Injection, доступный только в PreparedStatement.

Ответ 6

Постановка статична, а подготовленный отчет динамичен.

Постановка подходит для DDL и подготовлена отчетность для DML.

Оператор медленнее, а подготовленный оператор - быстрее.

больше различий

Ответ 7

Невозможно выполнить CLOB в заявлении.

И: (OraclePreparedStatement) ps

Ответ 8

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

Ответ 9

  • Легче читать
  • Вы можете легко сделать строку запроса константой

Ответ 10

Оператор будет использоваться для выполнения статических операторов SQL и не может принимать входные параметры.

PreparedStatement будет использоваться для выполнения SQL-запросов много раз динамически. Он будет принимать входные параметры.

Ответ 11

Другая характеристика подготовленного или параметризованного запроса: Ссылка, взятая из этой статьи.

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

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

Некоторый параметр вроде предложения where, который не передается во время создания шаблона позднее, отправляет эти параметры в систему базы данных и систему использования базы данных SQL Statement и выполняет в соответствии с запросом.

Подготовленные утверждения очень полезны для SQL Injection, потому что приложение может подготовить параметр, используя различные методы и протоколы.

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

Ответ 12

Как указано mattjames

Использование Statement в JDBC должно быть на 100% локализовано для использования для DDL (ALTER, CREATE, GRANT и т.д.), поскольку это единственное утверждение типы, которые не могут принимать BIND VARIABLES. Подготовленные записи или CallableStatements следует использовать для КАЖДОГО ДРУГОГО типа заявления (DML, Запросы). Поскольку это типы операторов, которые принимают bind переменные.

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

Ответ 13

Statement интерфейс выполняет статические инструкции SQL без параметров

PreparedStatement интерфейс (расширение Statement) выполняет предварительно скомпилированный оператор SQL с параметрами/без параметров

  • Эффективен для повторных исполнений

  • Он предварительно скомпилирован, чтобы быстрее

Ответ 14

Не запутайтесь: просто помните

  1. Оператор используется для статических запросов, таких как DDL, т.е. create, drop, alter и prepareStatement используется для динамических запросов, например DML-запросов.
  2. В операторе запрос предварительно не скомпилирован, а в режиме prepareStatement запрос предварительно скомпилирован, поскольку этот метод prepareStatement эффективен по времени.
  3. prepareStatement принимает аргумент во время создания, в то время как Statement не принимает аргументы. Например, если вы хотите создать таблицу и вставить элемент, то :: Создать таблицу (статическую) с помощью Statement и Вставить элемент (динамический) с использованием prepareStatement.

Ответ 15

Я следовал всем ответам на этот вопрос, чтобы изменить работающий унаследованный код, используя - Statement (но с SQL-инъекциями) на решение, использующее PreparedStatement с гораздо более медленным кодом из-за плохого понимания семантики вокруг Statement.addBatch(String sql) и PreparedStatement.addBatch().

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

Мой сценарий был

    Statement statement = connection.createStatement();

        for (Object object : objectList) {
         //Create a query which would be different for each object 
         // Add this query to statement for batch using - statement.addBatch(query);
        }
   statement.executeBatch();

Итак, в приведенном выше коде у меня были тысячи различных запросов, все они были добавлены к одному и тому же оператору, и этот код работал быстрее, потому что операторы, которые не были кэшированы, были хорошими, и этот код редко выполнялся в приложении.

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

    List<PreparedStatement> pStatements = new ArrayList<>();    
                        for (Object object : objectList) {
                         //Create a query which would be different for each object 
                         PreparedStatement pStatement =connection.prepareStatement(query);
                         // This query can't be added to batch because its a different query so I used list. 
                   //Set parameter to pStatement using object 
                         pStatements.add(pStatement);
                        }// Object loop
    // In place of statement.executeBatch(); , I had to loop around the list & execute each update separately          
    for (PreparedStatement ps : pStatements) {
                ps.executeUpdate();
            }

Итак, вы видите, я начал создавать тысячи объектов PreparedStatement и затем в конечном итоге не смог использовать пакетирование, потому что мой сценарий требовал, чтобы - были тысячи запросов UPDATE или INSERT, и все эти запросы оказались разными.

Исправление внедрения SQL было обязательным без каких-либо затрат снижения производительности, и я не думаю, что это возможно с PreparedStatement в этом сценарии.

Кроме того, когда вы используете встроенную функцию пакетирования, вам нужно беспокоиться о закрытии только одного оператора, но при этом подходе List необходимо закрыть оператор перед повторным использованием, повторное использование PreparedStatement