Meskipun benar bahwa, dalam banyak kasus, pernyataan SQL dasar akan menyelesaikan pekerjaan untuk banyak perubahan atau kueri basis data, ini sering kali merupakan praktik terbaik untuk memanfaatkan fleksibilitas dan keuntungan yang diberikan kepada Anda dengan menggunakan PreparedStatements
.
Perbedaan utama antara pernyataan JDBC standar dan PreparedStatement
paling baik ditentukan oleh manfaat bahwa PreparedStatement
memberi Anda dan aplikasi Anda. Di bawah ini kita akan memeriksa tiga keuntungan inti dari PreparedStatements
atas pernyataan JDBC/SQL biasa.
Pencegahan Injeksi SQL
Manfaat pertama menggunakan PreparedStatement
apakah Anda dapat memanfaatkan banyak .setXYZ()
metode, seperti .setString()
, yang memungkinkan kode Anda secara otomatis keluar dari karakter khusus seperti kutipan dalam pernyataan SQL yang diteruskan, mencegah SQL injection
yang selalu berbahaya menyerang.
Misalnya, dalam pernyataan SQL standar, mungkin tipikal untuk menyisipkan nilai langsung sejajar dengan pernyataan, seperti:
statement = "INSERT INTO books (title, primary_author, published_date) VALUES ('" + book.getTitle() + "', '" + book.getPrimaryAuthor() + "', '" + new Timestamp(book.getPublishedDate().getTime()) + "'";
Ini akan memaksa Anda untuk mengeksekusi kode Anda sendiri untuk mencegah injeksi SQL dengan menghilangkan tanda kutip dan karakter khusus lainnya dari nilai yang dimasukkan.
Sebaliknya, sebuah PreparedStatement
mungkin dipanggil sebagai berikut, menggunakan .setXYZ()
metode untuk menyisipkan nilai dengan karakter otomatis keluar selama eksekusi metode:
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();
Pra-Kompilasi
Manfaat lain dari PreparedStatement
adalah bahwa SQL itu sendiri pre-compiled
satu kali dan kemudian disimpan dalam memori oleh sistem, daripada dikompilasi setiap kali pernyataan dipanggil. Ini memungkinkan eksekusi yang lebih cepat, terutama ketika PreparedStatement
digunakan bersama dengan batches
, yang memungkinkan Anda menjalankan seri (atau batches
) dari pernyataan SQL sekaligus selama koneksi database tunggal.
Misalnya, di sini kita memiliki fungsi yang menerima List
dari buku-buku. Untuk setiap book
dalam daftar, kami ingin menjalankan INSERT
pernyataan, tetapi kami akan menambahkan semuanya ke kumpulan PreparedStatements
dan jalankan semuanya dalam satu gerakan:
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();
}
}
Penyisipan Tipe Data Abnormal dalam Pernyataan SQL
Keuntungan terakhir dari PreparedStatements
yang akan kita bahas adalah kemampuan untuk memasukkan tipe data abnormal ke dalam pernyataan SQL itu sendiri, seperti Timestamp
, InputStream
, dan banyak lagi.
Misalnya, kita dapat menggunakan PreparedStatement
untuk menambahkan foto sampul ke catatan buku kami menggunakan .setBinaryStream()
metode:
ps = connection.prepareStatement("INSERT INTO books (cover_photo) VALUES (?)");
ps.setBinaryStream(1, book.getPhoto());
ps.executeUpdate();