Unterschied zwischen Anweisung und PreparedStatement

Java Top

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Übersicht

In diesem Tutorial werden die Unterschiede zwischen den Anweisungen von JDBC Statement und PreparedStatement untersucht . Wir werden nicht abdeckt Callablestatement , eine JDBC - API - Schnittstelle , die verwendet wird , gespeicherte Prozeduren auszuführen.

2. JDBC-API-Schnittstelle

Sowohl Statement als auch PreparedStatement können zum Ausführen von SQL-Abfragen verwendet werden. Diese Schnittstellen sehen sehr ähnlich aus. Sie unterscheiden sich jedoch erheblich in Funktionen und Leistung:

  • Anweisung - Wird zum Ausführen von stringbasierten SQL- Abfragen verwendet
  • PreparedStatement - Wird zum Ausführen parametrisierter SQL-Abfragen verwendet

Um Statement und PreparedStatement in unseren Beispielen verwenden zu können, deklarieren wir den h2- JDBC-Connector als Abhängigkeit in unserer Datei pom.xml :

 com.h2database h2 1.4.200 

Definieren wir eine Entität, die wir in diesem Artikel verwenden werden:

public class PersonEntity { private int id; private String name; // standard setters and getters }

3. Aussage

Erstens akzeptiert die Anweisungsschnittstelle Zeichenfolgen als SQL-Abfragen. Daher wird der Code weniger lesbar, wenn wir SQL-Zeichenfolgen verketten:

public void insert(PersonEntity personEntity) { String query = "INSERT INTO persons(id, name) VALUES(" + personEntity.getId() + ", '" + personEntity.getName() + "')"; Statement statement = connection.createStatement(); statement.executeUpdate(query); }

Zweitens ist es anfällig für SQL-Injection . Die nächsten Beispiele veranschaulichen diese Schwäche.

In der ersten Zeile setzt das Update die Spalte " Name " in allen Zeilen auf " Hacker ", da alles nach "-" in SQL als Kommentar interpretiert wird und die Bedingungen der Update-Anweisung ignoriert werden. In der zweiten Zeile schlägt die Einfügung fehl, da das Anführungszeichen in der Spalte " Name " nicht maskiert wurde:

dao.update(new PersonEntity(1, "hacker' --")); dao.insert(new PersonEntity(1, "O'Brien"))

Drittens übergibt JDBC die Abfrage mit Inline-Werten an die Datenbank . Daher gibt es keine Abfrageoptimierung, und vor allem muss das Datenbankmodul alle Überprüfungen sicherstellen . Außerdem wird die Abfrage in der Datenbank nicht als dieselbe angezeigt und verhindert die Verwendung des Caches . Ebenso müssen Stapelaktualisierungen separat ausgeführt werden:

public void insert(List personEntities) { for (PersonEntity personEntity: personEntities) { insert(personEntity); } }

Viertens eignet sich die Anweisungsschnittstelle für DDL-Abfragen wie CREATE, ALTER und DROP :

public void createTables() { String query = "create table if not exists PERSONS (ID INT, NAME VARCHAR(45))"; connection.createStatement().executeUpdate(query); }

Schließlich kann die Anweisungsschnittstelle nicht zum Speichern und Abrufen von Dateien und Arrays verwendet werden .

4. PreparedStatement

Erstens erweitert das PreparedStatement die Anweisungsschnittstelle . Es verfügt über Methoden zum Binden verschiedener Objekttypen , einschließlich Dateien und Arrays. Daher wird der Code leicht verständlich :

public void insert(PersonEntity personEntity) { String query = "INSERT INTO persons(id, name) VALUES( ?, ?)"; PreparedStatement preparedStatement = connection.prepareStatement(query); preparedStatement.setInt(1, personEntity.getId()); preparedStatement.setString(2, personEntity.getName()); preparedStatement.executeUpdate(); }

Zweitens schützt es vor SQL-Injection , indem der Text für alle angegebenen Parameterwerte maskiert wird:

@Test void whenInsertAPersonWithQuoteInText_thenItNeverThrowsAnException() { assertDoesNotThrow(() -> dao.insert(new PersonEntity(1, "O'Brien"))); } @Test void whenAHackerUpdateAPerson_thenItUpdatesTheTargetedPerson() throws SQLException { dao.insert(Arrays.asList(new PersonEntity(1, "john"), new PersonEntity(2, "skeet"))); dao.update(new PersonEntity(1, "hacker' --")); List result = dao.getAll(); assertEquals(Arrays.asList( new PersonEntity(1, "hacker' --"), new PersonEntity(2, "skeet")), result); }

Drittens verwendet das PreparedStatement eine Vorkompilierung . Sobald die Datenbank eine Abfrage erhält, überprüft sie den Cache, bevor die Abfrage vorkompiliert wird. Folglich , wenn es nicht im Cache gespeichert wird, wird der Datenbank - Engine für die nächste Nutzung speichern.

Darüber hinaus beschleunigt diese Funktion die Kommunikation zwischen der Datenbank und der JVM über ein Nicht-SQL-Binärprotokoll. Das heißt, die Pakete enthalten weniger Daten, sodass die Kommunikation zwischen den Servern schneller verläuft.

Viertens bietet das PreparedStatement eine Stapelausführung während einer einzelnen Datenbankverbindung . Lassen Sie uns dies in Aktion sehen:

public void insert(List personEntities) throws SQLException { String query = "INSERT INTO persons(id, name) VALUES( ?, ?)"; PreparedStatement preparedStatement = connection.prepareStatement(query); for (PersonEntity personEntity: personEntities) { preparedStatement.setInt(1, personEntity.getId()); preparedStatement.setString(2, personEntity.getName()); preparedStatement.addBatch(); } preparedStatement.executeBatch(); }

Als Nächstes bietet das PreparedStatement eine einfache Möglichkeit zum Speichern und Abrufen von Dateien mithilfe der BLOB- und CLOB -Datentypen . Ebenso hilft es, Listen zu speichern, indem java.sql.Array in ein SQL-Array konvertiert wird .

Schließlich implementiert das PreparedStatement Methoden wie getMetadata () , die Informationen über das zurückgegebene Ergebnis enthalten.

5. Schlussfolgerung

In diesem Tutorial haben wir die Hauptunterschiede zwischen PreparedStatement und Statement vorgestellt . Beide Schnittstellen bieten Methoden zum Ausführen von SQL-Abfragen. Es ist jedoch besser geeignet, Statement für DDL-Abfragen und PreparedStatement für DML-Abfragen zu verwenden.

Wie üblich sind alle Codebeispiele auf GitHub verfügbar.

Java unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs