PreparedStatement
Requêtes paramétrées sûres
PreparedStatement est une leçon Java Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Java Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Java Academy comprend 4 leçons au total.
Pourquoi utiliser PreparedStatement ?
Construire du SQL en concaténant les données saisies par l'utilisateur est dangereux et lent.
PreparedStatement résout ces deux problèmes :
- Sécurité — les valeurs sont envoyées séparément du SQL, ce qui empêche l'injection SQL.
- Performances — la base de données peut analyser et planifier la requête une fois, puis la réutiliser.
Le problème de l'injection SQL
Imaginez que vous construisiez une requête par concaténation de chaînes. Si un utilisateur saisit '; DROP TABLE users; -- comme nom, le SQL concaténé exécute cette valeur comme une commande.
Il s'agit d'une injection SQL, l'une des vulnérabilités du Web les plus anciennes et les plus dommageables. PreparedStatement la rend impossible par conception.
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);
}
}Marqueurs
Dans un PreparedStatement, écrivez un ? pour chaque valeur que vous fournirez ultérieurement.
Liez ensuite les valeurs à l'aide de méthodes de définition typées :
ps.setString(1, name)ps.setInt(2, age)
Les indices des paramètres commencent à 1, conformément à l'ordre des marqueurs ?.
Une requête sûre
Créez l'instruction avec prepareStatement, liez les paramètres, puis appelez executeQuery.
La valeur n'entre jamais dans le texte SQL ; l'injection est donc impossible, quelles que soient les données saisies par l'utilisateur.
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());
}
}
}Lier plusieurs paramètres
Chaque ? doit faire l'objet de son propre appel de méthode de définition. L'ordre est important : le paramètre 1 correspond au premier ?, le paramètre 2 au deuxième, et ainsi de suite.
Utilisez la méthode de définition correspondant au type de la colonne — setInt, setString, setDouble, setBoolean, etc.
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());
}
}
}Gérer NULL
Pour lier un NULL SQL, utilisez setNull(index, type) avec une constante java.sql.Types.
Ne transmettez pas une valeur Java null à setString en espérant que cela fonctionne — soyez explicite :
ps.setNull(2, java.sql.Types.INTEGER)
Récupérer les clés générées
Après un INSERT, vous avez souvent besoin de l'identifiant généré automatiquement.
Transmettez Statement.RETURN_GENERATED_KEYS lors de la préparation, puis lisez les clés avec 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());
}
}
}Insertions par lots
Insérer des milliers de lignes une par une est lent. Utilisez un traitement par lots :
- Liez les paramètres, puis appelez
ps.addBatch(). - Répétez l'opération pour chaque ligne.
- Appelez
ps.executeBatch()une seule fois.
Les lignes sont ainsi envoyées ensemble, ce qui réduit considérablement les allers-retours.
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());
}
}
}Réutiliser une instruction
Un seul PreparedStatement peut être exécuté de nombreuses fois avec des paramètres différents.
Liez de nouveau les marqueurs et appelez execute une nouvelle fois. La base de données réutilise le plan d'exécution mis en cache, ce qui explique pourquoi les instructions préparées sont plus rapides pour les requêtes répétées.
Ne concaténez jamais
La règle d'or : toute valeur variable doit être un paramètre ?.
Seuls les identifiants fixes contrôlés par le code (comme un nom de colonne figurant sur une liste blanche) peuvent être concaténés — et même dans ce cas, validez-les par rapport à une liste autorisée. Les données fournies par l'utilisateur sont toujours liées, jamais concaténées.
Fermeture et portée de réutilisation
Un PreparedStatement est lié à sa Connection et doit être fermé une fois terminé.
Dans un bloc try avec ressources, déclarez l'instruction afin qu'elle se ferme avant la connexion. Si vous réutilisez une instruction de nombreuses fois dans une boucle, préparez-la une seule fois en dehors de la boucle et reliez uniquement les paramètres à l'intérieur — la préparer à chaque itération élimine le plan mis en cache.
Vérification rapide
Pourquoi un PreparedStatement empêche-t-il l’injection SQL ?
Récapitulatif
Vous avez appris à écrire des requêtes sûres et rapides :
- Utilisez des paramètres de remplacement
?et des mutateurs typés (indice commençant à 1). - Liez les valeurs avec
setString,setInt,setNull, etc. - Récupérez les clés générées automatiquement avec
RETURN_GENERATED_KEYSetgetGeneratedKeys. - Regroupez de nombreuses écritures avec
addBatch+executeBatch. - Ne concaténez jamais les données saisies par l’utilisateur dans SQL.
Questions Fréquemment Posées
La leçon « PreparedStatement » est-elle gratuite ?
Oui — le texte complet de « PreparedStatement » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Java Academy, passe à CoddyKit PRO. Le cours Java Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « PreparedStatement » ?
Requêtes paramétrées sûres Tu pratiques Java Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Java Academy ?
Aucune expérience préalable n'est requise. Java Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « PreparedStatement » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Java Academy ?
Oui. Chaque leçon Java Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.