PreparedStatement
Veilige query's met parameters
PreparedStatement is een gratis Java Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Java Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Java Academy bevat in totaal 4 lessen.
Waarom PreparedStatement?
SQL opbouwen door invoer van de gebruiker aaneen te schakelen is gevaarlijk en traag.
PreparedStatement lost beide problemen op:
- Veiligheid — waarden worden afzonderlijk van de SQL verzonden, waardoor SQL-injectie wordt voorkomen.
- Prestaties — de database kan de query één keer ontleden en plannen en deze daarna opnieuw gebruiken.
Het probleem van SQL-injectie
Stel dat je een query opbouwt door tekenreeksen aaneen te schakelen. Als een gebruiker '; DROP TABLE users; -- als naam invoert, voert de samengevoegde SQL dat uit als een opdracht.
Dit is SQL-injectie, een van de oudste en schadelijkste kwetsbaarheden op internet. PreparedStatement maakt dit door het ontwerp onmogelijk.
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);
}
}Plaatsaanduidingen
In een PreparedStatement schrijf je voor elke waarde die je later aanlevert een ?.
Daarna koppel je waarden met setters voor het juiste type:
ps.setString(1, name)ps.setInt(2, age)
Parameterindexen beginnen bij 1, in dezelfde volgorde als de ?-tekens.
Een veilige query
Maak de instructie met prepareStatement, koppel de parameters en roep daarna executeQuery aan.
De waarde komt nooit in aanraking met de SQL-tekst, dus injectie kan niet plaatsvinden, ongeacht wat de gebruiker invoert.
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());
}
}
}Meerdere parameters koppelen
Elke ? krijgt een eigen aanroep van een setter. De volgorde is belangrijk: parameter 1 is de eerste ?, parameter 2 de tweede, enzovoort.
Gebruik de setter die overeenkomt met het kolomtype — setInt, setString, setDouble, setBoolean enzovoort.
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());
}
}
}NULL verwerken
Gebruik setNull(index, type) met een constante van java.sql.Types om een SQL-NULL te koppelen.
Geef geen Java-null door aan setString in de hoop dat het werkt — wees expliciet:
ps.setNull(2, java.sql.Types.INTEGER)
Gegenereerde sleutels ophalen
Na een INSERT heb je vaak de automatisch gegenereerde id nodig.
Geef Statement.RETURN_GENERATED_KEYS door bij het voorbereiden en lees daarna 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());
}
}
}Batchgewijs invoegen
Duizenden rijen één voor één invoegen is traag. Gebruik batchverwerking:
- Koppel de parameters en roep daarna
ps.addBatch()aan. - Herhaal dit voor elke rij.
- Roep één keer
ps.executeBatch()aan.
Hiermee verstuur je de rijen samen en verminder je het aantal netwerkritten drastisch.
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());
}
}
}Een Statement hergebruiken
Eén PreparedStatement kan vaak worden uitgevoerd met verschillende parameters.
Koppel de plaatsaanduidingen opnieuw en roep execute nogmaals aan. De database hergebruikt het gecachte uitvoeringsplan. Daarom zijn voorbereide statements sneller bij herhaalde queries.
Nooit aaneenschakelen
De gouden regel: elke waarde die kan variëren moet een parameter met ? zijn.
Alleen vaste, door de code beheerde identifiers (zoals een kolomnaam op een goedkeuringslijst) mogen worden aaneengeschakeld — en zelfs dan moet je ze controleren aan de hand van een toestemmingslijst. Door de gebruiker aangeleverde gegevens worden altijd gekoppeld en nooit aaneengeschakeld.
Sluiten en bereik voor hergebruik
Een PreparedStatement is gekoppeld aan zijn Connection en moet na gebruik worden gesloten.
Declareer de instructie binnen try-with-resources, zodat deze vóór de verbinding wordt gesloten. Als je een instructie vaak opnieuw gebruikt in een lus, bereid je deze één keer buiten de lus voor en koppel je alleen binnen de lus de parameters opnieuw — bij elke herhaling opnieuw voorbereiden gooit het gecachte plan weg.
Korte controle
Waarom voorkomt een PreparedStatement SQL-injectie?
Samenvatting
Je hebt geleerd veilige, snelle query's te schrijven:
- Gebruik
?-plaatshouders en setters met het juiste type (index vanaf 1). - Koppel waarden met
setString,setInt,setNull, enzovoort. - Haal automatisch gegenereerde sleutels op met
RETURN_GENERATED_KEYSengetGeneratedKeys. - Verwerk veel schrijfbewerkingen in één batch met
addBatch+executeBatch. - Voeg gebruikersinvoer nooit samen met SQL.
Leer Java met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 104
- Lessen
- 374
Veelgestelde vragen
Is de les “PreparedStatement” gratis?
Ja — de volledige tekst van “PreparedStatement” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Java Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Java Academy bevat in totaal 4 lessen.
Wat leer ik in “PreparedStatement”?
Veilige query's met parameters Je oefent met Java Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Java Academy te beginnen?
Ervaring vooraf is niet nodig. Java Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “PreparedStatement”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Java Academy?
Ja. Elke les over Java Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- De basis van JDBC
- PreparedStatement
- Transacties
- Connection pooling met HikariCP