Selvom det er rigtigt, at en grundlæggende SQL-sætning i mange tilfælde vil få arbejdet gjort for mange databaseændringer eller forespørgsler, er det ofte en bedste praksis at gøre brug af den fleksibilitet og fordele, du får ved at bruge PreparedStatements
.
De primære forskelle mellem en standard JDBC-sætning og en PreparedStatement
er bedst defineret af fordele at en PreparedStatement
giver dig og din ansøgning. Nedenfor vil vi undersøge de tre kernefordele ved PreparedStatements
over almindelige JDBC/SQL-sætninger.
SQL-injektionsforebyggelse
Den første fordel ved at bruge en PreparedStatement
er du kan drage fordel af de mange .setXYZ()
metoder, såsom .setString()
, som tillader din kode automatisk at undslippe specialtegn såsom anførselstegn inden for den beståede SQL-sætning, hvilket forhindrer den altid farlige SQL injection
angreb.
I en standard SQL-sætning kan det f.eks. være typisk at indsætte værdier direkte inline med sætningen, som sådan:
statement = "INSERT INTO books (title, primary_author, published_date) VALUES ('" + book.getTitle() + "', '" + book.getPrimaryAuthor() + "', '" + new Timestamp(book.getPublishedDate().getTime()) + "'";
Dette ville tvinge dig til at udføre din egen kode for at forhindre SQL-injektioner ved at undslippe anførselstegn og andre specialtegn fra de indsatte værdier.
Omvendt en PreparedStatement
kan påberåbes som følger ved at bruge .setXYZ()
metoder til at indsætte værdier med automatisk tegn-escape under metodeudførelse:
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();
Pre-compilation
En anden fordel ved en PreparedStatement
er, at selve SQL'en er pre-compiled
en enkelt gang og derefter gemt i hukommelsen af systemet, i stedet for at blive kompileret hver gang sætningen kaldes. Dette giver mulighed for hurtigere eksekvering, især når en PreparedStatement
bruges sammen med batches
, som giver dig mulighed for at udføre en serie (eller batch
) af SQL-sætninger på én gang under en enkelt databaseforbindelse.
For eksempel har vi her en funktion, der accepterer en List
af bøger. For hver book
på listen ønsker vi at udføre en INSERT
erklæring, men vi vil tilføje dem alle til en batch af PreparedStatements
og udføre dem alle i ét hug:
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();
}
}
Indsættelse af unormale datatyper i SQL-sætning
Den sidste fordel ved PreparedStatements
som vi vil dække er evnen til at indsætte unormale datatyper i selve SQL-sætningen, såsom Timestamp
, InputStream
, og mange flere.
For eksempel kan vi bruge en PreparedStatement
at tilføje et forsidebillede til vores bogjournal ved hjælp af .setBinaryStream()
metode:
ps = connection.prepareStatement("INSERT INTO books (cover_photo) VALUES (?)");
ps.setBinaryStream(1, book.getPhoto());
ps.executeUpdate();