Maîtrisez MySQL avec PHP, découvrez VSCode pour le développement et Adminer pour l'administration. Du débutant à l'expert en base de données.
Installation complète de MySQL, configuration PHP et première connexion.
<?php
// test_mysql.php - Vérifier la connexion MySQL
echo "Test de l'installation MySQL + PHP
";
// 1. Vérifier l'extension MySQL
if (extension_loaded('mysqli')) {
echo "✅ Extension MySQLi : INSTALLÉE
";
} else {
echo "❌ Extension MySQLi : NON INSTALLÉE
";
}
if (extension_loaded('pdo_mysql')) {
echo "✅ Extension PDO MySQL : INSTALLÉE
";
} else {
echo "❌ Extension PDO MySQL : NON INSTALLÉE
";
}
// 2. Informations PHP
echo "Informations PHP :
";
echo "Version PHP : " . phpversion() . "
";
echo "Extensions MySQL disponibles :
";
$extensions = get_loaded_extensions();
$mysql_extensions = array_filter($extensions, function($ext) {
return stripos($ext, 'mysql') !== false || stripos($ext, 'pdo') !== false;
});
foreach ($mysql_extensions as $ext) {
echo "- $ext
";
}
// 3. Test de connexion basique
echo "Test de connexion :
";
// Configuration de base (à adapter)
$host = 'localhost';
$username = 'root';
$password = '';
try {
// Test avec MySQLi
$mysqli = new mysqli($host, $username, $password);
if ($mysqli->connect_error) {
echo "❌ MySQLi : " . $mysqli->connect_error . "
";
} else {
echo "✅ MySQLi : Connexion réussie
";
echo "Version MySQL : " . $mysqli->server_info . "
";
$mysqli->close();
}
// Test avec PDO
$pdo = new PDO("mysql:host=$host", $username, $password);
echo "✅ PDO : Connexion réussie
";
} catch (Exception $e) {
echo "❌ Erreur de connexion : " . $e->getMessage() . "
";
}
// 4. Configuration recommandée php.ini
echo "Configuration recommandée php.ini :
";
echo "
extension=mysqli
extension=pdo_mysql
mysql.default_host = localhost
mysql.default_user = root
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off
";
?>
Optimisez VSCode avec les meilleures extensions et configurations pour le développement MySQL/PHP.
{
// Configuration PHP
"php.validate.enable": true,
"php.validate.executablePath": "/usr/bin/php",
"php.suggest.basic": false,
"intelephense.files.maxSize": 5000000,
// Configuration MySQL
"sqltools.connections": [
{
"name": "MySQL Local",
"driver": "MySQL",
"server": "localhost",
"port": 3306,
"username": "root",
"password": "",
"database": "test"
}
],
// Configuration générale
"editor.fontSize": 14,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"files.associations": {
"*.php": "php",
"*.sql": "sql"
},
// Auto-formatting
"editor.formatOnSave": true,
"[php]": {
"editor.defaultFormatter": "junstyle.php-cs-fixer"
},
"[sql]": {
"editor.defaultFormatter": "bradymholt.pgformatter"
}
}
{
"PDO Connection": {
"prefix": "pdo-connect",
"body": [
"try {",
" \\$pdo = new PDO('mysql:host=${1:localhost};dbname=${2:database}', '${3:username}', '${4:password}');",
" \\$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);",
" \\$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);",
"} catch (PDOException \\$e) {",
" die('Erreur de connexion : ' . \\$e->getMessage());",
"}"
]
},
"MySQLi Connection": {
"prefix": "mysqli-connect",
"body": [
"\\$mysqli = new mysqli('${1:localhost}', '${2:username}', '${3:password}', '${4:database}');",
"if (\\$mysqli->connect_error) {",
" die('Erreur de connexion : ' . \\$mysqli->connect_error);",
"}",
"\\$mysqli->set_charset('utf8');"
]
},
"SELECT Query PDO": {
"prefix": "pdo-select",
"body": [
"\\$sql = \"SELECT ${1:*} FROM ${2:table} WHERE ${3:condition} = ?\";",
"\\$stmt = \\$pdo->prepare(\\$sql);",
"\\$stmt->execute([\\$${4:param}]);",
"\\$${5:result} = \\$stmt->fetchAll();"
]
},
"INSERT Query PDO": {
"prefix": "pdo-insert",
"body": [
"\\$sql = \"INSERT INTO ${1:table} (${2:columns}) VALUES (${3:placeholders})\";",
"\\$stmt = \\$pdo->prepare(\\$sql);",
"\\$stmt->execute([${4:values}]);"
]
}
}
Découvrez Adminer, l'alternative légère et puissante à phpMyAdmin pour gérer vos bases de données.
Maîtrisez PDO et MySQLi pour vous connecter de manière sécurisée à MySQL.
<?php
// ✅ PDO - Plus flexible et sécurisé
class DatabasePDO {
private $pdo;
private $host = 'localhost';
private $dbname = 'ma_base';
private $username = 'root';
private $password = '';
public function __construct() {
try {
$dsn = "mysql:host={$this->host};dbname={$this->dbname};charset=utf8mb4";
$this->pdo = new PDO($dsn, $this->username, $this->password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]);
} catch (PDOException $e) {
die('Erreur : ' . $e->getMessage());
}
}
public function getConnection() {
return $this->pdo;
}
}
// Utilisation
$database = new DatabasePDO();
$pdo = $database->getConnection();
echo "✅ Connexion PDO réussie !";
?>
<?php
// MySQLi - Spécifique à MySQL
class DatabaseMySQLi {
private $mysqli;
private $host = 'localhost';
private $username = 'root';
private $password = '';
private $database = 'ma_base';
public function __construct() {
$this->mysqli = new mysqli(
$this->host,
$this->username,
$this->password,
$this->database
);
if ($this->mysqli->connect_error) {
die('Erreur : ' . $this->mysqli->connect_error);
}
$this->mysqli->set_charset('utf8mb4');
}
public function getConnection() {
return $this->mysqli;
}
}
// Utilisation
$database = new DatabaseMySQLi();
$mysqli = $database->getConnection();
echo "✅ Connexion MySQLi réussie !";
?>
<?php
// Connexion PDO simple pour débuter
$host = 'localhost';
$dbname = 'ma_base';
$username = 'root';
$password = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]);
echo "✅ Connexion réussie !";
} catch (PDOException $e) {
die("❌ Erreur de connexion : " . $e->getMessage());
}
// Maintenant vous pouvez utiliser $pdo pour vos requêtes
?>
Code prêt à l'emploi pour démarrer rapidement avec MySQL et PHP.
<?php
// connexion.php - Fichier de connexion à recopier
$host = 'localhost';
$dbname = 'ma_base';
$username = 'root';
$password = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]);
echo "✅ Connexion réussie !";
} catch (PDOException $e) {
die("❌ Erreur de connexion : " . $e->getMessage());
}
?>
<?php
// select.php - Exemples de SELECT
include 'connexion.php';
// 1. SELECT simple - tous les utilisateurs
$sql = "SELECT * FROM users";
$stmt = $pdo->query($sql);
$users = $stmt->fetchAll();
echo "<h3>Tous les utilisateurs :</h3>";
foreach ($users as $user) {
echo "- " . $user['nom'] . " " . $user['prenom'] . " (" . $user['email'] . ")<br>";
}
// 2. SELECT avec WHERE - utilisateur spécifique
$email = 'jean.dupont@email.com';
$sql = "SELECT * FROM users WHERE email = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user) {
echo "<h3>Utilisateur trouvé :</h3>";
echo "Nom : " . $user['nom'] . "<br>";
echo "Email : " . $user['email'] . "<br>";
} else {
echo "Aucun utilisateur trouvé avec cet email.";
}
// 3. SELECT avec LIMIT - pagination
$page = 1;
$parPage = 10;
$offset = ($page - 1) * $parPage;
$sql = "SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$parPage, $offset]);
$users = $stmt->fetchAll();
echo "<h3>Utilisateurs (page $page) :</h3>";
foreach ($users as $user) {
echo "- " . $user['nom'] . "<br>";
}
// 4. SELECT avec COUNT
$sql = "SELECT COUNT(*) as total FROM users";
$stmt = $pdo->query($sql);
$total = $stmt->fetch()['total'];
echo "<p>Total utilisateurs : $total</p>";
?>
<?php
// insert.php - Exemples d'INSERT
include 'connexion.php';
// 1. INSERT simple
$nom = 'Martin';
$prenom = 'Pierre';
$email = 'pierre.martin@email.com';
$age = 25;
$sql = "INSERT INTO users (nom, prenom, email, age, created_at) VALUES (?, ?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([$nom, $prenom, $email, $age]);
$userId = $pdo->lastInsertId();
echo "✅ Utilisateur créé avec l'ID : $userId<br>";
// 2. INSERT avec tableau associatif
$userData = [
'nom' => 'Durand',
'prenom' => 'Marie',
'email' => 'marie.durand@email.com',
'age' => 28
];
$columns = implode(', ', array_keys($userData));
$placeholders = ':' . implode(', :', array_keys($userData));
$sql = "INSERT INTO users ($columns, created_at) VALUES ($placeholders, NOW())";
$stmt = $pdo->prepare($sql);
// Lier les valeurs
foreach ($userData as $key => $value) {
$stmt->bindValue(":$key", $value);
}
if ($stmt->execute()) {
echo "✅ Utilisateur " . $userData['prenom'] . " créé !<br>";
} else {
echo "❌ Erreur lors de la création<br>";
}
// 3. INSERT multiple (batch)
$users = [
['nom' => 'Petit', 'prenom' => 'Paul', 'email' => 'paul.petit@email.com', 'age' => 22],
['nom' => 'Grand', 'prenom' => 'Sophie', 'email' => 'sophie.grand@email.com', 'age' => 35],
['nom' => 'Blanc', 'prenom' => 'Luc', 'email' => 'luc.blanc@email.com', 'age' => 41]
];
$sql = "INSERT INTO users (nom, prenom, email, age, created_at) VALUES (?, ?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$pdo->beginTransaction();
try {
foreach ($users as $user) {
$stmt->execute([$user['nom'], $user['prenom'], $user['email'], $user['age']]);
}
$pdo->commit();
echo "✅ " . count($users) . " utilisateurs créés en lot !<br>";
} catch (Exception $e) {
$pdo->rollback();
echo "❌ Erreur lors de la création en lot : " . $e->getMessage() . "<br>";
}
// 4. INSERT avec vérification d'existence
$emailCheck = 'test@email.com';
$sql = "SELECT COUNT(*) FROM users WHERE email = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$emailCheck]);
if ($stmt->fetchColumn() == 0) {
// L'email n'existe pas, on peut insérer
$sql = "INSERT INTO users (nom, prenom, email, age, created_at) VALUES (?, ?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute(['Test', 'User', $emailCheck, 30]);
echo "✅ Nouvel utilisateur créé !<br>";
} else {
echo "⚠️ Un utilisateur avec cet email existe déjà.<br>";
}
?>
<?php
// update.php - Exemples d'UPDATE
include 'connexion.php';
// 1. UPDATE simple - modifier un utilisateur
$userId = 1;
$nouvelAge = 26;
$nouvelEmail = 'nouveau.email@example.com';
$sql = "UPDATE users SET age = ?, email = ?, updated_at = NOW() WHERE id = ?";
$stmt = $pdo->prepare($sql);
$result = $stmt->execute([$nouvelAge, $nouvelEmail, $userId]);
if ($stmt->rowCount() > 0) {
echo "✅ Utilisateur $userId mis à jour !<br>";
} else {
echo "⚠️ Aucun utilisateur trouvé avec l'ID $userId<br>";
}
// 2. UPDATE conditionnel - modifier par email
$email = 'pierre.martin@email.com';
$nouveauNom = 'Martin-Dupont';
$sql = "UPDATE users SET nom = ?, updated_at = NOW() WHERE email = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$nouveauNom, $email]);
echo "Nombre de lignes modifiées : " . $stmt->rowCount() . "<br>";
// 3. UPDATE multiple - modifier plusieurs champs
$userId = 2;
$updates = [
'prenom' => 'Marie-Claire',
'age' => 29,
'email' => 'marie-claire.durand@email.com'
];
// Construire la requête dynamiquement
$setParts = [];
$params = [];
foreach ($updates as $column => $value) {
$setParts[] = "$column = ?";
$params[] = $value;
}
$params[] = $userId; // Pour le WHERE
$sql = "UPDATE users SET " . implode(', ', $setParts) . ", updated_at = NOW() WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
if ($stmt->rowCount() > 0) {
echo "✅ Utilisateur $userId mis à jour avec " . count($updates) . " champs !<br>";
}
// 4. UPDATE avec vérification d'existence
$email = 'utilisateur@inexistant.com';
$newAge = 35;
// Vérifier si l'utilisateur existe
$sql = "SELECT id FROM users WHERE email = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user) {
$sql = "UPDATE users SET age = ?, updated_at = NOW() WHERE email = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$newAge, $email]);
echo "✅ Âge mis à jour pour $email<br>";
} else {
echo "❌ Utilisateur non trouvé : $email<br>";
}
// 5. UPDATE avec CASE (conditionnel SQL)
$sql = "UPDATE users SET
statut = CASE
WHEN age < 18 THEN 'mineur'
WHEN age >= 18 AND age < 65 THEN 'actif'
ELSE 'senior'
END,
updated_at = NOW()";
$stmt = $pdo->prepare($sql);
$stmt->execute();
echo "✅ Statuts mis à jour pour " . $stmt->rowCount() . " utilisateurs<br>";
// 6. UPDATE avec JOIN (avancé)
$sql = "UPDATE users u
INNER JOIN user_profiles p ON u.id = p.user_id
SET u.last_login = NOW(),
p.login_count = p.login_count + 1
WHERE u.email = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute(['user@example.com']);
echo "✅ Dernière connexion mise à jour<br>";
?>
<?php
// delete.php - Exemples de DELETE
include 'connexion.php';
// 1. DELETE simple - supprimer un utilisateur par ID
$userId = 1;
$sql = "DELETE FROM users WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId]);
if ($stmt->rowCount() > 0) {
echo "✅ Utilisateur $userId supprimé !<br>";
} else {
echo "⚠️ Aucun utilisateur trouvé avec l'ID $userId<br>";
}
// 2. DELETE par email
$email = 'user.to.delete@email.com';
$sql = "DELETE FROM users WHERE email = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$email]);
echo "Nombre d'utilisateurs supprimés : " . $stmt->rowCount() . "<br>";
// 3. DELETE avec vérification préalable
$userIdToDelete = 5;
// Vérifier si l'utilisateur existe
$sql = "SELECT nom, prenom FROM users WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userIdToDelete]);
$user = $stmt->fetch();
if ($user) {
// L'utilisateur existe, on peut le supprimer
$sql = "DELETE FROM users WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userIdToDelete]);
echo "✅ Utilisateur " . $user['prenom'] . " " . $user['nom'] . " supprimé !<br>";
} else {
echo "❌ Utilisateur avec l'ID $userIdToDelete introuvable<br>";
}
// 4. DELETE conditionnel - supprimer les anciens comptes
$dateLimit = date('Y-m-d', strtotime('-1 year'));
$sql = "DELETE FROM users WHERE created_at < ? AND last_login IS NULL";
$stmt = $pdo->prepare($sql);
$stmt->execute([$dateLimit]);
echo "✅ " . $stmt->rowCount() . " comptes inactifs supprimés<br>";
// 5. DELETE avec LIMIT - supprimer en lot
$sql = "DELETE FROM users WHERE statut = 'inactive' LIMIT 10";
$stmt = $pdo->prepare($sql);
$stmt->execute();
echo "✅ " . $stmt->rowCount() . " utilisateurs inactifs supprimés (max 10)<br>";
// 6. Soft DELETE - marquer comme supprimé au lieu de supprimer
$userId = 8;
// Au lieu de DELETE, on met un flag deleted_at
$sql = "UPDATE users SET deleted_at = NOW() WHERE id = ? AND deleted_at IS NULL";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId]);
if ($stmt->rowCount() > 0) {
echo "✅ Utilisateur $userId marqué comme supprimé (soft delete)<br>";
} else {
echo "⚠️ Utilisateur déjà supprimé ou introuvable<br>";
}
// 7. DELETE avec sauvegarde dans table d'archivage
$userId = 10;
$pdo->beginTransaction();
try {
// 1. Copier dans la table d'archive
$sql = "INSERT INTO users_deleted SELECT *, NOW() as deleted_date FROM users WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId]);
// 2. Supprimer de la table principale
$sql = "DELETE FROM users WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId]);
$pdo->commit();
echo "✅ Utilisateur $userId archivé et supprimé !<br>";
} catch (Exception $e) {
$pdo->rollback();
echo "❌ Erreur lors de l'archivage : " . $e->getMessage() . "<br>";
}
// 8. DELETE avec relations (CASCADE simulé)
$userId = 12;
$pdo->beginTransaction();
try {
// Supprimer d'abord les données liées
$sql = "DELETE FROM user_posts WHERE user_id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId]);
$postsDeleted = $stmt->rowCount();
$sql = "DELETE FROM user_comments WHERE user_id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId]);
$commentsDeleted = $stmt->rowCount();
// Puis supprimer l'utilisateur
$sql = "DELETE FROM users WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId]);
if ($stmt->rowCount() > 0) {
$pdo->commit();
echo "✅ Utilisateur $userId et ses données supprimés ($postsDeleted posts, $commentsDeleted commentaires)<br>";
} else {
$pdo->rollback();
echo "❌ Utilisateur $userId introuvable<br>";
}
} catch (Exception $e) {
$pdo->rollback();
echo "❌ Erreur lors de la suppression : " . $e->getMessage() . "<br>";
}
?>
<?php
// transaction.php - Exemples de TRANSACTIONS
include 'connexion.php';
// 1. Transaction simple - transfert d'argent
$compteSource = 1;
$compteDestination = 2;
$montant = 100.00;
$pdo->beginTransaction();
try {
// Vérifier le solde du compte source
$sql = "SELECT solde FROM comptes WHERE id = ? FOR UPDATE";
$stmt = $pdo->prepare($sql);
$stmt->execute([$compteSource]);
$soldeSource = $stmt->fetchColumn();
if ($soldeSource < $montant) {
throw new Exception("Solde insuffisant");
}
// Débiter le compte source
$sql = "UPDATE comptes SET solde = solde - ? WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$montant, $compteSource]);
// Créditer le compte destination
$sql = "UPDATE comptes SET solde = solde + ? WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$montant, $compteDestination]);
// Enregistrer la transaction
$sql = "INSERT INTO transactions (compte_source, compte_destination, montant, date_transaction)
VALUES (?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([$compteSource, $compteDestination, $montant]);
$pdo->commit();
echo "✅ Transfert de $montant € réussi !<br>";
} catch (Exception $e) {
$pdo->rollback();
echo "❌ Transfert échoué : " . $e->getMessage() . "<br>";
}
// 2. Transaction complexe - création utilisateur complet
$userData = [
'nom' => 'Nouveau',
'prenom' => 'Utilisateur',
'email' => 'nouveau@exemple.com',
'age' => 25
];
$pdo->beginTransaction();
try {
// 1. Créer l'utilisateur
$sql = "INSERT INTO users (nom, prenom, email, age, created_at) VALUES (?, ?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userData['nom'], $userData['prenom'], $userData['email'], $userData['age']]);
$userId = $pdo->lastInsertId();
// 2. Créer son profil
$sql = "INSERT INTO user_profiles (user_id, bio, avatar, created_at) VALUES (?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId, 'Nouveau membre', 'default.jpg']);
// 3. Créer ses paramètres
$sql = "INSERT INTO user_settings (user_id, notifications, theme, language) VALUES (?, ?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId, 1, 'dark', 'fr']);
// 4. L'ajouter au groupe par défaut
$sql = "INSERT INTO user_groups (user_id, group_id, joined_at) VALUES (?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([$userId, 1]); // Groupe "Utilisateurs"
$pdo->commit();
echo "✅ Utilisateur complet créé avec l'ID : $userId<br>";
} catch (Exception $e) {
$pdo->rollback();
echo "❌ Création utilisateur échouée : " . $e->getMessage() . "<br>";
}
// 3. Transaction avec savepoint (point de sauvegarde)
$pdo->beginTransaction();
try {
// Opération 1
$sql = "INSERT INTO categories (nom) VALUES (?)";
$stmt = $pdo->prepare($sql);
$stmt->execute(['Nouvelle Catégorie']);
$categoryId = $pdo->lastInsertId();
// Point de sauvegarde
$pdo->exec("SAVEPOINT sp1");
try {
// Opération 2 (peut échouer)
$sql = "INSERT INTO products (nom, category_id, prix) VALUES (?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute(['Produit Test', $categoryId, 'prix_invalide']); // Erreur volontaire
} catch (Exception $e2) {
// Retour au point de sauvegarde
$pdo->exec("ROLLBACK TO SAVEPOINT sp1");
echo "⚠️ Erreur produit, mais catégorie conservée : " . $e2->getMessage() . "<br>";
}
$pdo->commit();
echo "✅ Transaction partielle réussie (catégorie créée)<br>";
} catch (Exception $e) {
$pdo->rollback();
echo "❌ Transaction complètement échouée : " . $e->getMessage() . "<br>";
}
// 4. Transaction avec gestion d'erreurs avancée
function transfererArgent($pdo, $compteA, $compteB, $montant) {
$pdo->beginTransaction();
try {
// Vérifications préalables
$sql = "SELECT id, solde, statut FROM comptes WHERE id IN (?, ?) FOR UPDATE";
$stmt = $pdo->prepare($sql);
$stmt->execute([$compteA, $compteB]);
$comptes = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($comptes) != 2) {
throw new Exception("Un ou plusieurs comptes introuvables");
}
$soldeA = null;
$soldeB = null;
foreach ($comptes as $compte) {
if ($compte['statut'] != 'actif') {
throw new Exception("Compte {$compte['id']} inactif");
}
if ($compte['id'] == $compteA) $soldeA = $compte['solde'];
if ($compte['id'] == $compteB) $soldeB = $compte['solde'];
}
if ($soldeA < $montant) {
throw new Exception("Solde insuffisant sur le compte $compteA");
}
// Effectuer le transfert
$sql = "UPDATE comptes SET solde = solde - ?, updated_at = NOW() WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$montant, $compteA]);
$sql = "UPDATE comptes SET solde = solde + ?, updated_at = NOW() WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$montant, $compteB]);
// Historique
$sql = "INSERT INTO transferts (compte_source, compte_destination, montant, statut, created_at)
VALUES (?, ?, ?, 'completed', NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([$compteA, $compteB, $montant]);
$pdo->commit();
return ['success' => true, 'message' => "Transfert de $montant € réussi"];
} catch (Exception $e) {
$pdo->rollback();
// Logger l'erreur
$sql = "INSERT INTO error_logs (operation, error_message, created_at) VALUES (?, ?, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute(['transfert', $e->getMessage()]);
return ['success' => false, 'message' => $e->getMessage()];
}
}
// Utilisation de la fonction
$result = transfererArgent($pdo, 1, 2, 50.00);
if ($result['success']) {
echo "✅ " . $result['message'] . "<br>";
} else {
echo "❌ " . $result['message'] . "<br>";
}
// 5. Transaction avec retry automatique
function executerAvecRetry($pdo, $callback, $maxRetries = 3) {
$attempts = 0;
while ($attempts < $maxRetries) {
try {
$pdo->beginTransaction();
$result = $callback($pdo);
$pdo->commit();
return ['success' => true, 'result' => $result, 'attempts' => $attempts + 1];
} catch (Exception $e) {
$pdo->rollback();
$attempts++;
// Si c'est un deadlock, on peut retry
if (strpos($e->getMessage(), 'Deadlock') !== false && $attempts < $maxRetries) {
sleep(1); // Attendre avant de réessayer
continue;
}
return ['success' => false, 'error' => $e->getMessage(), 'attempts' => $attempts];
}
}
}
// Exemple d'utilisation du retry
$result = executerAvecRetry($pdo, function($pdo) {
// Opération complexe qui peut causer un deadlock
$sql = "UPDATE stock SET quantite = quantite - 1 WHERE product_id = ? AND quantite > 0";
$stmt = $pdo->prepare($sql);
$stmt->execute([1]);
if ($stmt->rowCount() == 0) {
throw new Exception("Stock insuffisant");
}
return "Stock mis à jour";
});
if ($result['success']) {
echo "✅ " . $result['result'] . " (tentatives: " . $result['attempts'] . ")<br>";
} else {
echo "❌ " . $result['error'] . " après " . $result['attempts'] . " tentatives<br>";
}
?>
Create, Read, Update, Delete - Maîtrisez toutes les opérations de base de données.
<?php
/**
* Classe CRUD Complète avec PDO
* Gestion sécurisée des opérations de base de données
*/
class CRUDManager {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
/**
* CREATE - Insérer des données
*/
public function create($table, $data) {
try {
// Préparer les colonnes et placeholders
$columns = implode(', ', array_keys($data));
$placeholders = ':' . implode(', :', array_keys($data));
$sql = "INSERT INTO {$table} ({$columns}) VALUES ({$placeholders})";
$stmt = $this->pdo->prepare($sql);
// Lier les valeurs
foreach ($data as $key => $value) {
$stmt->bindValue(":{$key}", $value);
}
$stmt->execute();
return $this->pdo->lastInsertId();
} catch (PDOException $e) {
throw new Exception("Erreur lors de l'insertion : " . $e->getMessage());
}
}
/**
* READ - Sélectionner des données
*/
public function read($table, $conditions = [], $options = []) {
try {
$sql = "SELECT * FROM {$table}";
$params = [];
// Ajouter les conditions WHERE
if (!empty($conditions)) {
$whereClause = [];
foreach ($conditions as $key => $value) {
$whereClause[] = "{$key} = :{$key}";
$params[":{$key}"] = $value;
}
$sql .= " WHERE " . implode(' AND ', $whereClause);
}
// Ajouter ORDER BY
if (isset($options['order_by'])) {
$sql .= " ORDER BY " . $options['order_by'];
if (isset($options['order_dir'])) {
$sql .= " " . strtoupper($options['order_dir']);
}
}
// Ajouter LIMIT
if (isset($options['limit'])) {
$sql .= " LIMIT " . (int)$options['limit'];
if (isset($options['offset'])) {
$sql .= " OFFSET " . (int)$options['offset'];
}
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
// Retourner un seul résultat ou tous
if (isset($options['single']) && $options['single']) {
return $stmt->fetch();
}
return $stmt->fetchAll();
} catch (PDOException $e) {
throw new Exception("Erreur lors de la lecture : " . $e->getMessage());
}
}
/**
* UPDATE - Mettre à jour des données
*/
public function update($table, $data, $conditions) {
try {
// Préparer la clause SET
$setClause = [];
foreach ($data as $key => $value) {
$setClause[] = "{$key} = :set_{$key}";
}
// Préparer la clause WHERE
$whereClause = [];
foreach ($conditions as $key => $value) {
$whereClause[] = "{$key} = :where_{$key}";
}
$sql = "UPDATE {$table} SET " . implode(', ', $setClause) .
" WHERE " . implode(' AND ', $whereClause);
$stmt = $this->pdo->prepare($sql);
// Lier les valeurs SET
foreach ($data as $key => $value) {
$stmt->bindValue(":set_{$key}", $value);
}
// Lier les valeurs WHERE
foreach ($conditions as $key => $value) {
$stmt->bindValue(":where_{$key}", $value);
}
$stmt->execute();
return $stmt->rowCount();
} catch (PDOException $e) {
throw new Exception("Erreur lors de la mise à jour : " . $e->getMessage());
}
}
/**
* DELETE - Supprimer des données
*/
public function delete($table, $conditions) {
try {
$whereClause = [];
$params = [];
foreach ($conditions as $key => $value) {
$whereClause[] = "{$key} = :{$key}";
$params[":{$key}"] = $value;
}
$sql = "DELETE FROM {$table} WHERE " . implode(' AND ', $whereClause);
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->rowCount();
} catch (PDOException $e) {
throw new Exception("Erreur lors de la suppression : " . $e->getMessage());
}
}
/**
* MÉTHODES UTILITAIRES
*/
// Compter les enregistrements
public function count($table, $conditions = []) {
try {
$sql = "SELECT COUNT(*) as total FROM {$table}";
$params = [];
if (!empty($conditions)) {
$whereClause = [];
foreach ($conditions as $key => $value) {
$whereClause[] = "{$key} = :{$key}";
$params[":{$key}"] = $value;
}
$sql .= " WHERE " . implode(' AND ', $whereClause);
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetch()['total'];
} catch (PDOException $e) {
throw new Exception("Erreur lors du comptage : " . $e->getMessage());
}
}
// Vérifier l'existence
public function exists($table, $conditions) {
return $this->count($table, $conditions) > 0;
}
// Requête personnalisée
public function query($sql, $params = []) {
try {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
// Retourner selon le type de requête
if (stripos($sql, 'SELECT') === 0) {
return $stmt->fetchAll();
} elseif (stripos($sql, 'INSERT') === 0) {
return $this->pdo->lastInsertId();
} else {
return $stmt->rowCount();
}
} catch (PDOException $e) {
throw new Exception("Erreur lors de l'exécution : " . $e->getMessage());
}
}
// Commencer une transaction
public function beginTransaction() {
return $this->pdo->beginTransaction();
}
// Valider une transaction
public function commit() {
return $this->pdo->commit();
}
// Annuler une transaction
public function rollback() {
return $this->pdo->rollback();
}
}
// EXEMPLES D'UTILISATION
// Initialisation de la connexion
try {
$pdo = new PDO('mysql:host=localhost;dbname=ma_base;charset=utf8mb4', 'root', '', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]);
} catch (PDOException $e) {
die('Erreur de connexion : ' . $e->getMessage());
}
$crud = new CRUDManager($pdo);
// CREATE - Créer un utilisateur
$userId = $crud->create('users', [
'nom' => 'Dupont',
'prenom' => 'Jean',
'email' => 'jean.dupont@email.com',
'age' => 30,
'created_at' => date('Y-m-d H:i:s')
]);
echo "Utilisateur créé avec l'ID : " . $userId . "\n";
// READ - Lire des utilisateurs
$users = $crud->read('users',
['age' => 30], // Conditions
['order_by' => 'nom', 'order_dir' => 'ASC', 'limit' => 10] // Options
);
foreach ($users as $user) {
echo "Utilisateur : " . $user['prenom'] . " " . $user['nom'] . "\n";
}
// READ - Lire un seul utilisateur
$user = $crud->read('users',
['id' => $userId],
['single' => true]
);
// UPDATE - Mettre à jour un utilisateur
$rowsUpdated = $crud->update('users',
['age' => 31, 'updated_at' => date('Y-m-d H:i:s')], // Nouvelles données
['id' => $userId] // Conditions
);
echo "Nombre de lignes mises à jour : " . $rowsUpdated . "\n";
// COUNT - Compter les utilisateurs
$totalUsers = $crud->count('users');
$adultUsers = $crud->count('users', ['age >=' => 18]);
echo "Total utilisateurs : " . $totalUsers . "\n";
echo "Utilisateurs majeurs : " . $adultUsers . "\n";
// EXISTS - Vérifier l'existence
if ($crud->exists('users', ['email' => 'jean.dupont@email.com'])) {
echo "L'email existe déjà\n";
}
// TRANSACTION - Exemple avec transaction
try {
$crud->beginTransaction();
$userId1 = $crud->create('users', ['nom' => 'Test1', 'email' => 'test1@email.com']);
$userId2 = $crud->create('users', ['nom' => 'Test2', 'email' => 'test2@email.com']);
$crud->commit();
echo "Transaction réussie\n";
} catch (Exception $e) {
$crud->rollback();
echo "Transaction échouée : " . $e->getMessage() . "\n";
}
// DELETE - Supprimer un utilisateur
$rowsDeleted = $crud->delete('users', ['id' => $userId]);
echo "Nombre de lignes supprimées : " . $rowsDeleted . "\n";
// REQUÊTE PERSONNALISÉE
$results = $crud->query(
"SELECT nom, COUNT(*) as count FROM users GROUP BY nom HAVING count > 1",
[]
);
foreach ($results as $result) {
echo "Nom en doublon : " . $result['nom'] . " (" . $result['count'] . " fois)\n";
}
?>
Jointures, sous-requêtes, fonctions d'agrégation et optimisation des performances.
Index, cache, monitoring et meilleures pratiques pour des performances optimales.
<?php
class OptimizedDatabase extends CRUDManager {
private $cache = [];
private $queryStats = [];
// Pool de connexions
private static $connections = [];
public function getOptimizedConnection($config) {
$key = md5(serialize($config));
if (!isset(self::$connections[$key])) {
self::$connections[$key] = new PDO(
$config['dsn'],
$config['username'],
$config['password'],
[
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
]
);
}
return self::$connections[$key];
}
// Cache intelligent
public function cachedQuery($sql, $params = [], $ttl = 3600) {
$cacheKey = 'query_' . md5($sql . serialize($params));
// Vérifier le cache
if (isset($this->cache[$cacheKey])) {
$data = $this->cache[$cacheKey];
if (time() - $data['time'] < $ttl) {
return $data['result'];
}
}
// Exécuter la requête
$result = $this->query($sql, $params);
// Mettre en cache
$this->cache[$cacheKey] = [
'result' => $result,
'time' => time()
];
return $result;
}
// Monitoring des performances
public function profiledQuery($sql, $params = []) {
$start = microtime(true);
$result = parent::query($sql, $params);
$duration = microtime(true) - $start;
// Stocker les statistiques
$this->queryStats[] = [
'sql' => $sql,
'duration' => $duration,
'timestamp' => time()
];
// Alerter si requête lente
if ($duration > 1.0) {
error_log("Requête lente détectée: {$duration}s - {$sql}");
}
return $result;
}
// Pagination optimisée
public function paginatedRead($table, $page = 1, $perPage = 20, $conditions = []) {
$offset = ($page - 1) * $perPage;
// Compter le total (avec cache)
$countSql = "SELECT COUNT(*) as total FROM {$table}";
if (!empty($conditions)) {
$whereClause = implode(' AND ', array_keys($conditions));
$countSql .= " WHERE {$whereClause}";
}
$total = $this->cachedQuery($countSql, $conditions, 300)[0]['total'];
// Récupérer les données
$data = $this->read($table, $conditions, [
'limit' => $perPage,
'offset' => $offset
]);
return [
'data' => $data,
'pagination' => [
'page' => $page,
'perPage' => $perPage,
'total' => $total,
'pages' => ceil($total / $perPage)
]
];
}
// Optimisation automatique des index
public function analyzeTable($table) {
// Analyser l'utilisation des index
$indexUsage = $this->query("SHOW INDEX FROM {$table}");
// Suggestions d'optimisation
$suggestions = [];
// Vérifier les colonnes sans index dans les WHERE
foreach ($this->queryStats as $stat) {
if (strpos($stat['sql'], "WHERE") !== false && $stat['duration'] > 0.5) {
$suggestions[] = "Considérer un index pour: {$table}";
}
}
return $suggestions;
}
// Rapport de performance
public function getPerformanceReport() {
$slowQueries = array_filter($this->queryStats, function($stat) {
return $stat['duration'] > 0.1;
});
$avgDuration = array_sum(array_column($this->queryStats, 'duration')) / count($this->queryStats);
return [
'total_queries' => count($this->queryStats),
'slow_queries' => count($slowQueries),
'average_duration' => $avgDuration,
'cache_hits' => count($this->cache),
'slowest_queries' => array_slice(
array_reverse(array_sort($this->queryStats, 'duration')),
0, 5
)
];
}
}
?>
Vous maîtrisez maintenant MySQL avec PHP, VSCode pour le développement et Adminer pour l'administration. Passez aux sujets avancés !
Installation MySQL • Configuration VSCode • Administration Adminer • Connexions PDO/MySQLi • CRUD Sécurisé • Requêtes Avancées • Optimisation