Es stimmt zwar, dass in vielen Fällen eine einfache SQL-Anweisung viele Datenbankänderungen oder -abfragen erledigt, aber es ist oft eine beste Vorgehensweise um die Flexibilität und Vorteile zu nutzen, die Ihnen durch die Verwendung von PreparedStatements
geboten werden .
Die Hauptunterschiede zwischen einer standardmäßigen JDBC-Anweisung und einer PreparedStatement
lassen sich am besten durch die Vorteile definieren dass ein PreparedStatement
bietet Ihnen und Ihrer Anwendung. Im Folgenden untersuchen wir die drei Hauptvorteile von PreparedStatements
über normale JDBC/SQL-Anweisungen.
SQL-Einschleusungsschutz
Der erste Vorteil der Verwendung eines PreparedStatement
So können Sie die Vielzahl von .setXYZ()
nutzen Methoden wie .setString()
, wodurch Ihr Code Sonderzeichen wie Anführungszeichen innerhalb der übergebenen SQL-Anweisung automatisch mit Escapezeichen versehen kann, wodurch die immer gefährliche SQL injection
verhindert wird Angriff.
Beispielsweise kann es in einer Standard-SQL-Anweisung typisch sein, Werte direkt in die Anweisung einzufügen, etwa so:
statement = "INSERT INTO books (title, primary_author, published_date) VALUES ('" + book.getTitle() + "', '" + book.getPrimaryAuthor() + "', '" + new Timestamp(book.getPublishedDate().getTime()) + "'";
Dies würde Sie dazu zwingen, Ihren eigenen Code auszuführen, um SQL-Injections zu verhindern, indem Sie Anführungszeichen und andere Sonderzeichen aus den eingefügten Werten maskieren.
Umgekehrt ein PreparedStatement
könnte wie folgt aufgerufen werden, indem .setXYZ()
verwendet wird Methoden zum Einfügen von Werten mit automatischem Zeichen-Escape während der Methodenausführung:
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();
Vorkompilierung
Ein weiterer Vorteil eines PreparedStatement
ist, dass das SQL selbst pre-compiled
ist ein einziges Mal und dann vom System im Speicher behalten, anstatt jedes Mal kompiliert zu werden, wenn die Anweisung aufgerufen wird. Dies ermöglicht eine schnellere Ausführung, insbesondere wenn ein PreparedStatement
wird in Verbindung mit batches
verwendet , mit denen Sie eine Serie ausführen können (oder batch
) von SQL-Anweisungen gleichzeitig während einer einzigen Datenbankverbindung.
Hier haben wir zum Beispiel eine Funktion, die eine List
akzeptiert von Büchern. Für jedes book
in der Liste wollen wir ein INSERT
ausführen -Anweisung, aber wir werden sie alle zu einem Stapel von PreparedStatements
hinzufügen und sie alle auf einen Schlag ausführen:
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();
}
}
Einfügung von anormalen Datentypen in eine SQL-Anweisung
Der letzte Vorteil von PreparedStatements
Was wir behandeln werden, ist die Möglichkeit, abnormale Datentypen in die SQL-Anweisung selbst einzufügen, wie z. B. Timestamp
, InputStream
, und viele mehr.
Beispielsweise können wir ein PreparedStatement
verwenden um ein Titelbild zu unserem Bucheintrag hinzuzufügen, indem Sie .setBinaryStream()
verwenden Methode:
ps = connection.prepareStatement("INSERT INTO books (cover_photo) VALUES (?)");
ps.setBinaryStream(1, book.getPhoto());
ps.executeUpdate();