# Bloc 2 - SGBDR Fiche 6 - MySQL avancé :Transaction Triggers et procédures stockées (MySQL)
Les procédures stockées représentent des programmes constitués d'une séquence d'instruction SQL. Elles sont stockées dans la base de données, et conçues pour effectuer une tâche particulière. Elles peuvent contenir une commande ou un ensemble de commandes SQL. Les procédures sont compilées et stockées sur le serveur. Grâce à elles, l'utilisateur n'a plus besoin de soumettre toute une commande, mais il fait référence à la procédure stockée correspondante.
C'est entendu. Passons à la vitesse supérieure avec une approche plus technique, en intégrant la syntaxe rigoureuse de MySQL pour la gestion des transactions et la logique procédurale.
Elles apportent entre autres :
- une meilleure sécurité (pas d'accès direct aux tables et pas d'erreur de commande),
- une diminution des redondances de code,
- une augmentation de la performance (baisse du trafic SQL sur le serveur).
Voici les deux sections enrichies avec des exemples concrets.
Les procédures stockées sont conservées sous forme **d'exécutable** en attente d'être appelées. Elles deviennent des objets de la base de données, tout comme les tables. L'application la plus simple est de rattacher des requêtes complexes à une base de données, afin que les utilisateurs n'aient pas à les taper plus d'une fois.
---
**Syntaxe générale**
### 1. Transactions et Propriétés ACID : Le "Tout ou Rien"
```sql
CREATEProcedure[nom_procedure]
{@parametre1type,@parametre2type}
AS[requete]
```
Une **transaction** est une unité logique de traitement. Pour garantir l'intégrité, MySQL (via le moteur **InnoDB**) s'appuie sur le modèle **ACID** :
*Exemple : procédure qui permet de sélectionner une date de commande (SQL SERVER) :*
***A (Atomicité) :** La transaction est une unité indivisible.
***C (Cohérence) :** On passe d'un état valide à un autre (respect des clés étrangères, types, etc.).
***I (Isolation) :** Les opérations d'une transaction sont invisibles pour les autres tant qu'elles ne sont pas validées.
***D (Durabilité) :** Une fois confirmées, les données sont gravées physiquement sur le disque.
**Exemple technique (Transfert bancaire) :**
```sql
CREATEPROCEDUREOrdersByDate
@StartDatedatetime,@EndDatedatetime
AS
SELECT*
FROMCOMMANDES
WHEREdate_cdeBETWEEN@StartDateAND@EndDate
```
STARTTRANSACTION;-- Début de l'unité de travail
Ici les paramètres sont en entrée, l'utilisateur doit fournir leurs variables. Les paramètres peuvent également être en sortie (on renvoie une valeur, on utilise alors le mot clé OUTPUT), ou même d'entrée et sortie. On indique les paramètres en précisant leur nom avec le symbole @. Le mot clé AS précise le début du corps de la procédure stockée.
-- Étape 1 : Débit
UPDATEcomptesSETsolde=solde-100WHEREid_client=1;
Exécution de la procédure :
-- Étape 2 : Crédit
UPDATEcomptesSETsolde=solde+100WHEREid_client=2;
```sql
DECLARE@StartDatedatetime
DECLARE@EndDatedatetime
-- Vérification logique (ex: solde négatif non autorisé)
IF(solde_insatisfaisant)THEN
ROLLBACK;-- Annulation totale : le client 1 récupère ses 100€
ELSE
COMMIT;-- Validation finale : les changements sont définitifs
ENDIF;
```
SET@StartDate='1/1/1997'
SET@EndDate='1/20/1997'
EXECUTEOrdersByDate@StartDate,@EndDate
```
### 2. Programmation Procédurale MySQL : Syntaxe Évoluée
Le langage procédural de MySQL permet d'encapsuler de la logique métier complexe. Contrairement au SQL standard, il nécessite l'utilisation de blocs `BEGIN ... END` et de mots-clés de contrôle de flux.
#### Éléments clés de la syntaxe :
## Triggers
***Déclaration :** Les variables locales doivent être déclarées au tout début du bloc avec `DECLARE`.
***Gestion d'erreurs (Handlers) :** Crucial pour automatiser le `ROLLBACK` en cas d'erreur SQL.
***Structures de contrôle :**`IF`, `CASE`, `WHILE`, `LOOP`.
Un trigger (ou déclencheur) est un code SQL associé à une seule table se déclenchant pour un ou plusieurs événements se produisant sur cette table. Ce code est exécuté par le SGBD chaque fois qu'un des événements se réalise.
**Exemple : Procédure avec gestionnaire d'erreur et transaction**
```SQL
DELIMITER //
Un trigger peut être déclenché par les événements suivants :
- l'insertion de tuples,
- la suppression de tuples,
- la modification de tuples dans une table.
CREATE PROCEDURE p_virement_securise(IN p_expediteur INT, IN p_destinataire INT, IN p_montant DECIMAL(10,2))
BEGIN
-- 1. Déclarer un gestionnaire en cas d'erreur SQL
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- En cas d'erreur (ex: clé étrangère inexistante), on annule tout
ROLLBACK;
RESIGNAL; -- Renvoie l'erreur au client
END;
L'événement déclencheur est donc l'une des commandes `INSERT`, `DELETE`, `UPDATE` ou l'une de leurs combinaisons possibles par l'opérateur booléen `OR`.
-- 2. Début de la logique métier
START TRANSACTION;
Le traitement qui est décrit pour un trigger est rédigé en Transact SQL (SQL Server) ou en PL/SQL (Oracle). Il peut agir sur les informations stockées dans la table pour laquelle il a été défini ou pour tout autre objet de la base de données.
-- Vérification du solde
IF (SELECT solde FROM comptes WHERE id = p_expediteur) < p_montant THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Solde insuffisant';
END IF;
La syntaxe simplifiée de la commande qui permet de créer un trigger est la suivante :
-- Exécution des mouvements
UPDATE comptes SET solde = solde - p_montant WHERE id = p_expediteur;
UPDATE comptes SET solde = solde + p_montant WHERE id = p_destinataire;
```sql
CREATETRIGGER[schema_name.]trigger_name
ON{table|view}
{FOR|AFTER|INSTEADOF}
{[INSERT][,][UPDATE][,][DELETE]}
AS{sql_statement[;]}
-- Si tout va bien, on valide
COMMIT;
END //
DELIMITER ;
```
Un trigger traitant des enregistrements en cours de modification, il est possible d'accéder à la valeur de l'enregistrement avant modification (`DELETED` sous SQL Server, `:OLD` sous Oracle) et après modification (`INSERTED` sous SQL Server, `:NEW` sous Oracle). Ces valeurs apparaissent en fonction du type de mise à jour.
### Résumé des différences techniques MySQL :
La modification d'un trigger peut également se faire par la commande de modification suivante :
| Fonctionnalité | Syntaxe MySQL | Note technique |
| --- | --- | --- |
| **Variables** | `DECLARE v_nom INT DEFAULT 0;` | Uniquement à l'intérieur d'un `BEGIN...END`. |
| **Assignation** | `SET v_nom = 10;` ou `SELECT col INTO v_nom...` | Utilise `INTO` pour stocker le résultat d'un SELECT. |
| **Annulation** | `SIGNAL SQLSTATE '45000'` | Provoque une erreur personnalisée pour stopper l'exécution. |
| **Délimiteur** | `DELIMITER //` | Nécessaire pour que le client SQL ne confonde pas le `;` interne avec la fin de la procédure. |
Pour supprimer un trigger, l'utilisateur doit formuler la commande suivante :
Les procédures stockées représentent des programmes constitués d'une séquence d'instructions SQL. Elles sont stockées dans la base de données et conçues pour effectuer une tâche particulière. Elles peuvent contenir une commande ou un ensemble de commandes SQL (Logique `IF`, boucles, etc.).
```sql
DROPTRIGGER[schema.]trigger;
```
Dans MySQL, les procédures sont pré-calculées sur le serveur, ce qui évite d'envoyer de lourdes requêtes sur le réseau : l'utilisateur appelle simplement le nom de la procédure.
*Exemples (SQL Server)*
### Avantages
```sql
CREATETRIGGERCheckStockONProductsFORUPDATE
AS
IF(SELECTInStockFROMINSERTED)<0
BEGIN
PRINT'Cannot oversell Products'
PRINT'Transaction has been cancelled'
ROLLBACK
END
```
***Performance :** Réduction du trafic réseau entre le client et le serveur.
***Sécurité :** On peut donner l'accès à une procédure sans donner l'accès direct aux tables.
***Maintenance :** La logique métier est centralisée à un seul endroit.
***Cohérence :** Garantit que la même opération est exécutée de la même manière par toutes les applications.
### Syntaxe de création
Pour créer une procédure dans MySQL, il faut changer temporairement le délimiteur de fin d'instruction (généralement `;`) pour que le serveur ne stoppe pas l'exécution à la première ligne interne.
Un **trigger** est un objet de la base de données associé à une table, qui s'exécute (se "déclenche") automatiquement lorsqu'un événement spécifique survient sur cette table.
### Événements déclencheurs
***INSERT** : Ajout de lignes.
***UPDATE** : Modification de lignes.
***DELETE** : Suppression de lignes.
### Moments du déclenchement
***BEFORE** : Avant que la modification ne soit appliquée (idéal pour la validation ou la modification de données entrantes).
***AFTER** : Après que la modification a été effectuée (idéal pour mettre à jour d'autres tables ou remplir des tables de log/audit).
### Mots-clés spécifiques
***OLD** : Accède aux valeurs de la ligne **avant** l'opération (disponible en `UPDATE` et `DELETE`).
***NEW** : Accède aux nouvelles valeurs **après/pendant** l'opération (disponible en `INSERT` et `UPDATE`).
### Exemple de Trigger (Blocage de suppression)
Voici l'adaptation de ton exemple : empêcher la suppression de clients habitant à 'Delhi'. Dans MySQL, pour annuler une transaction dans un trigger, on utilise souvent `SIGNAL SQLSTATE` pour lever une erreur.
```sql
CREATETRIGGERFORDELETEDelhiDelONCustomers
BEGIN
IF(SELECTstateFROM:OLD)='Delhi'
DELIMITER//
CREATETRIGGERbefore_delete_customers
BEFOREDELETEONcustomers
FOREACHROW
BEGIN
PRINT'Can not remove customers from Delhi'
PRINT'Transaction has been canceled'
ROLLBACK
END
END
IFOLD.city='Delhi'THEN
SIGNALSQLSTATE'45000'
SETMESSAGE_TEXT='Can not remove customers from Delhi. Transaction canceled.';