Database
 sql >> Base de données >  >> RDS >> Database

La différence entre une instruction JDBC et une instruction préparée

S'il est vrai que, dans de nombreux cas, une instruction SQL de base fera le travail pour de nombreuses modifications ou requêtes de base de données, il s'agit souvent d'une meilleure pratique pour profiter de la flexibilité et des avantages que vous offre l'utilisation de PreparedStatements .

Les principales différences entre une instruction JDBC standard et un PreparedStatement sont mieux définis par les avantages qu'un PreparedStatement vous offre, à vous et à votre application. Ci-dessous, nous examinerons les trois principaux avantages de PreparedStatements sur les instructions JDBC/SQL normales.

Prévention des injections SQL

Le premier avantage d'utiliser un PreparedStatement c'est que vous pouvez profiter de la multitude de .setXYZ() méthodes, telles que .setString() , qui permet à votre code d'échapper automatiquement les caractères spéciaux tels que les guillemets dans l'instruction SQL transmise, empêchant l'SQL injection toujours dangereuse attaque.

Par exemple, dans une instruction SQL standard, il peut être courant d'insérer des valeurs directement en ligne avec l'instruction, comme ceci :

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

Cela vous obligerait à exécuter votre propre code pour empêcher les injections SQL en échappant les guillemets et autres caractères spéciaux des valeurs insérées.

Inversement, un PreparedStatement peut être appelé comme suit, en utilisant le .setXYZ() méthodes pour insérer des valeurs avec un caractère d'échappement automatique lors de l'exécution de la méthode :

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é-compilation

Un autre avantage d'un PreparedStatement est que le SQL lui-même est pre-compiled une seule fois, puis conservée en mémoire par le système, plutôt que d'être compilée à chaque fois que l'instruction est appelée. Cela permet une exécution plus rapide, en particulier lorsqu'un PreparedStatement est utilisé en conjonction avec batches , qui vous permettent d'exécuter une série (ou batch ) d'instructions SQL en même temps au cours d'une seule connexion à la base de données.

Par exemple, nous avons ici une fonction qui accepte une List de livres. Pour chaque book dans la liste, on veut exécuter un INSERT déclaration, mais nous allons tous les ajouter à un lot de PreparedStatements et exécutez-les tous d'un seul coup :

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();
  }
}

Insertion de types de données anormaux dans l'instruction SQL

Le dernier avantage de PreparedStatements que nous couvrirons est la possibilité d'insérer des types de données anormaux dans l'instruction SQL elle-même, comme Timestamp , InputStream , et bien d'autres.

Par exemple, nous pouvons utiliser un PreparedStatement pour ajouter une photo de couverture à notre notice de livre en utilisant le .setBinaryStream() méthode :

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