sql >> Base de Datos >  >> RDS >> Database

La diferencia entre una declaración JDBC y una declaración preparada

Si bien es cierto que, en muchos casos, una instrucción SQL básica hará el trabajo para muchos cambios o consultas en la base de datos, a menudo es una práctica recomendada para hacer uso de la flexibilidad y las ventajas que le brinda el uso de PreparedStatements .

Las principales diferencias entre una instrucción JDBC estándar y una PreparedStatement se definen mejor por los beneficios que una PreparedStatement le ofrece a usted y a su aplicación. A continuación, examinaremos las tres ventajas principales de PreparedStatements sobre declaraciones regulares de JDBC/SQL.

Prevención de inyección SQL

El primer beneficio de usar un PreparedStatement es que puede aprovechar la multitud de .setXYZ() métodos, como .setString() , que permite que su código escape automáticamente de caracteres especiales como comillas dentro de la declaración SQL pasada, evitando la siempre peligrosa SQL injection ataque.

Por ejemplo, en una sentencia SQL estándar, puede ser típico insertar valores directamente en línea con la sentencia, así:

statement = "INSERT INTO books (title, primary_author, published_date) VALUES ('" + book.getTitle() + "', '" + book.getPrimaryAuthor() + "', '" + new Timestamp(book.getPublishedDate().getTime()) + "'";

Esto lo obligaría a ejecutar su propio código para evitar inyecciones de SQL escapando de las comillas y otros caracteres especiales de los valores insertados.

Por el contrario, una PreparedStatement podría invocarse de la siguiente manera, usando el .setXYZ() métodos para insertar valores con carácter de escape automático durante la ejecución del 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();

Precompilación

Otro beneficio de una PreparedStatement es que el propio SQL está pre-compiled una sola vez y luego el sistema lo retiene en la memoria, en lugar de compilarlo todas y cada una de las veces que se llama a la declaración. Esto permite una ejecución más rápida, particularmente cuando un PreparedStatement se usa junto con batches , que le permiten ejecutar una serie (o batch ) de sentencias SQL todas a la vez durante una única conexión a la base de datos.

Por ejemplo, aquí tenemos una función que acepta una List de libros. Para cada book en la lista, queremos ejecutar un INSERT declaración, pero vamos a agregarlos todos a un lote de PreparedStatements y ejecutarlos todos de una sola 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();
  }
}

Inserción de tipos de datos anormales en declaraciones SQL

La ventaja final de PreparedStatements lo que cubriremos es la capacidad de insertar tipos de datos anormales en la instrucción SQL, como Timestamp , InputStream y muchos más.

Por ejemplo, podemos usar un PreparedStatement para agregar una foto de portada a nuestro registro de libros usando .setBinaryStream() método:

ps = connection.prepareStatement("INSERT INTO books (cover_photo) VALUES (?)");
ps.setBinaryStream(1, book.getPhoto());
ps.executeUpdate();