Perbezaan Antara Penyataan dan Penyataan Bersedia

Java Teratas

Saya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:

>> SEMAK KURSUS

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan meneroka perbezaan antara antara muka Penyataan JDBC dan PreparedStatement . Kami tidak akan merangkumi CallableStatement , antara muka API JDBC yang digunakan untuk melaksanakan prosedur yang tersimpan.

2. Antaramuka API JDBC

Kedua-dua Penyata dan PreparedStatement boleh digunakan untuk melaksanakan pertanyaan SQL. Antaramuka ini kelihatan sangat serupa. Walau bagaimanapun, mereka berbeza antara satu sama lain dalam ciri dan prestasi:

  • Pernyataan - Digunakan untuk melaksanakan pertanyaan SQL berasaskan rentetan
  • PreparedStatement - Digunakan untuk melaksanakan pertanyaan SQL parameter

Untuk dapat menggunakan Penyataan dan Penyediaan Bersedia dalam contoh kami, kami akan menyatakan penyambung h2 JDBC sebagai pergantungan dalam fail pom.xml kami :

 com.h2database h2 1.4.200 

Mari tentukan entiti yang akan kita gunakan sepanjang artikel ini:

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

3. Penyataan

Pertama, antara muka Pernyataan menerima rentetan sebagai pertanyaan SQL. Oleh itu, kod menjadi kurang mudah dibaca apabila kita menggabungkan rentetan SQL:

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

Kedua, terdedah kepada suntikan SQL . Contoh seterusnya menggambarkan kelemahan ini.

Pada baris pertama, kemas kini akan menetapkan kolom " nama " pada semua baris menjadi " penggodam ", kerana apa pun setelah "-" ditafsirkan sebagai komentar dalam SQL dan syarat pernyataan kemas kini akan diabaikan. Pada baris kedua, sisipan akan gagal kerana petikan pada lajur " nama " belum terlepas:

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

Ketiga, JDBC menyampaikan pertanyaan dengan nilai sebaris ke pangkalan data . Oleh itu, tidak ada pengoptimuman pertanyaan, dan yang paling penting, mesin pangkalan data mesti memastikan semua pemeriksaan . Juga, pertanyaan tidak akan muncul sama dengan pangkalan data dan akan mengelakkan penggunaan cache . Begitu juga, kemas kini kumpulan perlu dijalankan secara berasingan:

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

Keempat, yang Penyata muka sesuai untuk pertanyaan DDL seperti CREATE, ALTER, dan DROP :

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

Akhir sekali, yang Penyata muka tidak boleh digunakan untuk menyimpan dan mendapatkan semula fail dan array .

4. Penyataan Bersedia

Pertama, PreparedStatement meluaskan antara muka Penyata . Ia mempunyai kaedah untuk mengikat pelbagai jenis objek , termasuk fail dan tatasusunan. Oleh itu, kod menjadi mudah difahami :

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(); }

Kedua, melindungi dari suntikan SQL , dengan melarikan teks untuk semua nilai parameter yang disediakan:

@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); }

Ketiga, PreparedStatement menggunakan pra-penyusunan . Sebaik sahaja pangkalan data mendapat pertanyaan, ia akan memeriksa cache sebelum menyusun pertanyaan terlebih dahulu. Akibatnya, jika tidak di-cache, mesin pangkalan data akan menyimpannya untuk penggunaan seterusnya.

Lebih-lebih lagi, ciri ini mempercepat komunikasi antara pangkalan data dan JVM melalui protokol binari bukan SQL. Maksudnya, ada kurang data dalam paket, jadi komunikasi antara pelayan berjalan lebih cepat.

Keempat, PreparedStatement menyediakan pelaksanaan kumpulan semasa sambungan pangkalan data tunggal . Mari lihat ini dalam tindakan:

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(); }

Seterusnya, PreparedStatement menyediakan cara mudah untuk menyimpan dan mengambil fail dengan menggunakan jenis data BLOB dan CLOB . Dalam urat yang sama, ia membantu menyimpan senarai dengan menukar java.sql.Array ke SQL Array.

Terakhir, PreparedStatement menerapkan kaedah seperti getMetadata () yang mengandungi maklumat mengenai hasil yang dikembalikan.

5. Kesimpulan

Dalam tutorial ini, kami membentangkan perbezaan utama antara Penyataan Bersedia dan Penyataan . Kedua-dua antara muka ini menawarkan kaedah untuk melaksanakan pertanyaan SQL, tetapi lebih sesuai menggunakan Pernyataan untuk pertanyaan DDL dan PreparedStatement untuk pertanyaan DML.

Seperti biasa, semua contoh kod boleh didapati di GitHub.

Bahagian bawah Java

Saya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:

>> SEMAK KURSUS