I když je pravda, že v mnoha případech základní příkaz SQL vykoná práci u mnoha změn v databázi nebo dotazů, často jde o nejlepší postup abyste využili flexibilitu a výhody, které vám nabízí používání PreparedStatements
.
Primární rozdíly mezi standardním příkazem JDBC a PreparedStatement
jsou nejlépe definovány podle výhod že PreparedStatement
poskytuje vám a vaší aplikaci. Níže prozkoumáme tři hlavní výhody PreparedStatements
přes běžné příkazy JDBC/SQL.
Prevence vkládání SQL
První výhoda použití PreparedStatement
můžete využít množství .setXYZ()
metody, jako je .setString()
, což umožňuje vašemu kódu automaticky uniknout speciálním znakům, jako jsou uvozovky v předávaném příkazu SQL, čímž se zabrání vždy nebezpečnému SQL injection
útok.
Například ve standardním příkazu SQL může být typické vkládat hodnoty přímo do řádku příkazu, například takto:
statement = "INSERT INTO books (title, primary_author, published_date) VALUES ('" + book.getTitle() + "', '" + book.getPrimaryAuthor() + "', '" + new Timestamp(book.getPublishedDate().getTime()) + "'";
To by vás donutilo spustit svůj vlastní kód, abyste zabránili injekcím SQL escapováním uvozovek a dalších speciálních znaků z vložených hodnot.
Naopak PreparedStatement
lze vyvolat následovně pomocí .setXYZ()
metody pro vkládání hodnot s automatickým escapováním znaků během provádění metody:
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();
Předkompilace
Další výhoda PreparedStatement
je, že samotný SQL je pre-compiled
jednou a poté uchován v paměti systémem, spíše než aby byl kompilován pokaždé, když je příkaz volán. To umožňuje rychlejší provádění, zvláště když PreparedStatement
se používá ve spojení s batches
, které vám umožní spustit sérii (nebo batch
) příkazů SQL najednou během jednoho připojení k databázi.
Například zde máme funkci, která přijímá List
knih. Pro každou book
v seznamu chceme provést INSERT
příkaz, ale všechny je přidáme do dávky PreparedStatements
a všechny je jedním šmahem popravit:
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();
}
}
Vložení abnormálních datových typů do příkazu SQL
Poslední výhoda PreparedStatements
kterou se budeme zabývat, je schopnost vkládat abnormální datové typy do samotného příkazu SQL, jako je Timestamp
, InputStream
a mnoho dalších.
Můžeme například použít PreparedStatement
k přidání titulní fotografie k našemu záznamu knihy pomocí .setBinaryStream()
metoda:
ps = connection.prepareStatement("INSERT INTO books (cover_photo) VALUES (?)");
ps.setBinaryStream(1, book.getPhoto());
ps.executeUpdate();