Java Academy · Pelajaran

PreparedStatement

Pertanyaan berparameter yang selamat

Pelajaran 2 daripada 413 langkah

PreparedStatement ialah pelajaran Java Academy percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Java Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Java Academy merangkumi sejumlah 4 pelajaran.

Mengapa PreparedStatement?

Membina SQL dengan mencantumkan masukan pengguna adalah berbahaya dan perlahan.

PreparedStatement menyelesaikan kedua-dua masalah:

  • Keselamatan — nilai dihantar secara berasingan daripada SQL, lalu mencegah suntikan SQL.
  • Prestasi — pangkalan data boleh menghuraikan dan merancang pertanyaan sekali, kemudian menggunakannya semula.

Masalah Suntikan SQL

Pertimbangkan pembinaan pertanyaan menggunakan pencantuman rentetan. Jika pengguna menaip '; DROP TABLE users; -- sebagai namanya, SQL yang dicantumkan akan melaksanakan input itu sebagai arahan.

Inilah suntikan SQL, salah satu kerentanan web yang paling lama wujud dan paling merosakkan. PreparedStatement menjadikannya mustahil secara reka bentuk.

public class Main {
    public static void main(String[] args) {
        String userInput = "'; DROP TABLE users; --";
        // Dangerous: never do this
        String unsafe = "SELECT * FROM users WHERE name = '" + userInput + "'";
        System.out.println("Injected SQL becomes:");
        System.out.println(unsafe);
    }
}

Pemegang Tempat

Dalam PreparedStatement, tulis ? untuk setiap nilai yang akan anda bekalkan kemudian.

Kemudian ikat nilai menggunakan penetap berjenis:

  • ps.setString(1, name)
  • ps.setInt(2, age)

Indeks parameter bermula daripada 1, selaras dengan susunan tanda ?.

Pertanyaan Selamat

Cipta pernyataan menggunakan prepareStatement, ikat parameter, kemudian panggil executeQuery.

Nilai itu tidak pernah menjadi sebahagian daripada teks SQL, jadi suntikan tidak boleh berlaku walau apa pun yang ditaip oleh pengguna.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Main {
    public static void main(String[] args) {
        String url = "jdbc:postgresql://localhost:5432/shop";
        String sql = "SELECT id FROM users WHERE name = ?";
        try (Connection conn = DriverManager.getConnection(url, "app", "secret");
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, "Ada");
            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) System.out.println(rs.getInt("id"));
            }
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }
}

Mengikat Berbilang Parameter

Setiap ? mendapat panggilan penetapnya sendiri. Susunan penting: parameter 1 ialah ? pertama, parameter 2 ialah yang kedua, dan seterusnya.

Gunakan penetap yang sepadan dengan jenis lajur — setInt, setString, setDouble, setBoolean dan sebagainya.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Main {
    public static void main(String[] args) {
        String url = "jdbc:postgresql://localhost:5432/shop";
        String sql = "INSERT INTO users(name, age, active) VALUES (?, ?, ?)";
        try (Connection conn = DriverManager.getConnection(url, "app", "secret");
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, "Grace");
            ps.setInt(2, 42);
            ps.setBoolean(3, true);
            int rows = ps.executeUpdate();
            System.out.println("Inserted " + rows + " row");
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }
}

Mengendalikan NULL

Untuk mengikat SQL NULL, gunakan setNull(index, type) bersama pemalar java.sql.Types.

Jangan hantar Java null kepada setString dengan harapan ia berfungsi — nyatakan jenisnya dengan jelas:

  • ps.setNull(2, java.sql.Types.INTEGER)

Mendapatkan Kunci Dijana

Selepas INSERT, anda sering memerlukan pengenal yang dijana secara automatik.

Hantar Statement.RETURN_GENERATED_KEYS semasa menyediakan pernyataan, kemudian baca ps.getGeneratedKeys().

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Main {
    public static void main(String[] args) {
        String url = "jdbc:postgresql://localhost:5432/shop";
        String sql = "INSERT INTO users(name) VALUES (?)";
        try (Connection conn = DriverManager.getConnection(url, "app", "secret");
             PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
            ps.setString(1, "Linus");
            ps.executeUpdate();
            try (ResultSet keys = ps.getGeneratedKeys()) {
                if (keys.next()) System.out.println("New id: " + keys.getLong(1));
            }
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }
}

Sisipan Berkelompok

Memasukkan ribuan baris satu pernyataan pada satu-satu masa adalah perlahan. Gunakan pemprosesan berkelompok:

  • Ikat parameter, kemudian panggil ps.addBatch().
  • Ulangi untuk setiap baris.
  • Panggil ps.executeBatch() sekali.

Ini menghantar baris secara bersama-sama dan mengurangkan perjalanan pergi balik dengan banyak.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Main {
    public static void main(String[] args) {
        String url = "jdbc:postgresql://localhost:5432/shop";
        String sql = "INSERT INTO tags(label) VALUES (?)";
        String[] labels = {"java", "jdbc", "sql"};
        try (Connection conn = DriverManager.getConnection(url, "app", "secret");
             PreparedStatement ps = conn.prepareStatement(sql)) {
            for (String label : labels) {
                ps.setString(1, label);
                ps.addBatch();
            }
            int[] counts = ps.executeBatch();
            System.out.println("Batched " + counts.length + " inserts");
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }
}

Menggunakan Semula Statement

Satu PreparedStatement boleh dilaksanakan berkali-kali dengan parameter yang berbeza.

Ikat semula pemegang tempat dan panggil execute sekali lagi. Pangkalan data menggunakan semula pelan pelaksanaan yang tersimpan, sebab itulah pernyataan yang disediakan lebih pantas untuk pertanyaan berulang.

Jangan Cantumkan

Peraturan utama: sebarang nilai yang berubah mesti menjadi parameter ?.

Hanya pengecam tetap yang dikawal oleh kod (seperti nama lajur yang disenarai benarkan) boleh dicantumkan — dan walaupun begitu, sahkan terhadap senarai izin. Data yang diberikan pengguna sentiasa diikat, bukan dicantumkan.

Menutup dan Menggunakan Semula dalam Skop

PreparedStatement terikat pada Connection dan hendaklah ditutup selepas selesai digunakan.

Dalam blok cuba dengan sumber, isytiharkan pernyataan supaya ia ditutup sebelum sambungan. Jika anda menggunakan semula pernyataan berkali-kali dalam gelung, sediakannya sekali di luar gelung dan hanya ikat semula parameter di dalamnya — menyediakan semula pada setiap lelaran membuang pelan tersimpan.

Semakan Pantas

Mengapakah PreparedStatement menghalang suntikan SQL?

Ringkasan

Anda telah mempelajari cara menulis pertanyaan yang selamat dan pantas:

  • Gunakan ruang letak ? dan penetap berjenis (indeks bermula pada 1).
  • Ikat nilai dengan setString, setInt, setNull dan sebagainya.
  • Dapatkan semula kunci yang dijana secara automatik dengan RETURN_GENERATED_KEYS dan getGeneratedKeys.
  • Kelompokkan banyak operasi tulis dengan addBatch + executeBatch.
  • Jangan sekali-kali menggabungkan masukan pengguna ke dalam SQL.
Percuma untuk bermula

Pelajari Java dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
104
Pelajaran
374

Soalan Lazim

Adakah pelajaran “PreparedStatement” percuma?

Ya — teks penuh “PreparedStatement” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Java Academy, tingkat taraf kepada CoddyKit PRO. Kursus Java Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “PreparedStatement”?

Pertanyaan berparameter yang selamat Anda berlatih Java Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Java Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Java Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.

Berapa lamakah pelajaran “PreparedStatement” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Java Academy ini?

Ya. Setiap pelajaran Java Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Asas JDBC
  2. PreparedStatement
  3. Transaksi
  4. Pengumpulan Sambungan dengan HikariCP
← Kembali ke Java Academy