Database
 sql >> Base de Dados >  >> RDS >> Database

A diferença entre uma declaração JDBC e uma declaração preparada


Embora seja verdade que, em muitos casos, uma instrução SQL básica fará o trabalho para muitas alterações ou consultas de banco de dados, geralmente é uma prática recomendada para fazer uso da flexibilidade e vantagens oferecidas a você usando PreparedStatements .

As principais diferenças entre uma instrução JDBC padrão e uma PreparedStatement são melhor definidos pelos benefícios que um PreparedStatement oferece a você e sua aplicação. Abaixo, examinaremos as três principais vantagens de PreparedStatements sobre instruções JDBC/SQL regulares.

Prevenção de injeção de SQL


O primeiro benefício de usar um PreparedStatement é que você pode tirar vantagem da multiplicidade de .setXYZ() métodos, como .setString() , que permite que seu código escape automaticamente de caracteres especiais, como aspas na instrução SQL passada, evitando a sempre perigosa SQL injection ataque.

Por exemplo, em uma instrução SQL padrão, pode ser comum inserir valores diretamente alinhados com a instrução, assim:
statement = "INSERT INTO books (title, primary_author, published_date) VALUES ('" + book.getTitle() + "', '" + book.getPrimaryAuthor() + "', '" + new Timestamp(book.getPublishedDate().getTime()) + "'";

Isso forçaria você a executar seu próprio código para evitar injeções de SQL escapando aspas e outros caracteres especiais dos valores inseridos.

Por outro lado, um PreparedStatement pode ser invocado da seguinte forma, usando o .setXYZ() métodos para inserir valores com escape automático de caracteres durante a execução do método:
ps = connection.prepareStatement("INSERT INTO books (title, primary_author, published_date) VALUES (?, ?, ?)");
ps.setString(1, book.getTitle());
ps.setString(2, book.getPrimaryAuthor());
ps.setTimestamp(3, new Timestamp(book.getPublishedDate().getTime()));
ps.executeUpdate();

Pré-compilação


Outro benefício de um PreparedStatement é que o próprio SQL é pre-compiled uma única vez e, em seguida, retido na memória pelo sistema, em vez de ser compilado toda vez que a instrução é chamada. Isso permite uma execução mais rápida, principalmente quando um PreparedStatement é usado em conjunto com batches , que permitem que você execute uma série (ou batch ) de instruções SQL de uma só vez durante uma única conexão de banco de dados.

Por exemplo, aqui temos uma função que aceita uma List de livros. Para cada book na lista, queremos executar um INSERT instrução, mas vamos adicionar todos eles a um lote de PreparedStatements e executá-los todos de uma só vez:
public void createBooks(List<Entity> books) throws SQLException {
  try (
    Connection connection = dataSource.getConnection();
    PreparedStatement ps = connection.prepareStatement("INSERT INTO books (title, primary_author, published_date) VALUES (?, ?, ?)");
  ) {
    for (Entity book : books) {
      ps.setString(1, book.getTitle());
      ps.setString(2, book.getPrimaryAuthor());
      ps.setTimestamp(3, new Timestamp(book.getPublishedDate().getTime()));

      ps.addBatch();
    }
    ps.executeBatch();
  }
}

Inserção de tipos de dados anormais na instrução SQL


A vantagem final de PreparedStatements que abordaremos é a capacidade de inserir tipos de dados anormais na própria instrução SQL, como Timestamp , InputStream , e muitos mais.

Por exemplo, podemos usar um PreparedStatement para adicionar uma foto de capa ao nosso registro de livro usando o .setBinaryStream() método:
ps = connection.prepareStatement("INSERT INTO books (cover_photo) VALUES (?)");
ps.setBinaryStream(1, book.getPhoto());
ps.executeUpdate();