Transactions et validation automatique (autocommit)
Maintenant que l'on est connecté via PDO, il faut comprendre
comment PDO gĂšre les transactions avant d'exĂ©cuter des requĂȘtes. Si l'on n'a
jamais utilisé les transactions, elles offrent 4 fonctionnalités majeures :
Atomicité, Consistance, Isolation et Durabilité (ACID). En d'autres termes,
n'importe quel travail menĂ© Ă bien dans une transaction, mĂȘme s'il est effectuĂ©
par Ă©tapes, est garanti d'ĂȘtre appliquĂ© Ă la base de donnĂ©es sans risque, et sans
interférence pour les autres connexions, quand il est validé. Le travail des transactions
peut Ă©galement ĂȘtre automatiquement annulĂ© Ă la demande (en supposant que
l'on n'ait encore rien validé), ce qui rend la gestion des erreurs bien plus
simple dans les scripts.
Les transactions sont typiquement implémentées pour appliquer
toutes les modifications en une seule fois ; ceci a le bel effet d'améliorer
radicalement l'efficacité des mises à jour. En d'autres termes,
les transactions rendent les scripts plus rapides et potentiellement plus
robustes (il faut les utiliser correctement pour jouir de ces bénéfices).
Malheureusement, toutes les bases de données ne prennent pas en charge les transactions,
donc PDO doit s'exécuter en mode "autocommit" lorsque l'on ouvre pour la premiÚre
fois la connexion. Le mode "autocommit" signifie que toutes les requĂȘtes que l'on
exécute ont leurs transactions implicites, si la base de données le prend en charge ou
aucune transaction si la base de données ne les prend pas en charge. En cas de besoin
d'une transaction, il faut utiliser la méthode PDO::beginTransaction()
pour l'initialiser. Si le pilote utilisé ne prend pas en charge les transactions, une
exception PDO sera lancée (en accord avec le gestionnaire d'erreurs : ceci est toujours
une erreur sérieuse). Une fois que l'on est dans une transaction, il faut utiliser
la fonction PDO::commit() ou la fonction PDO::rollBack()
pour la terminer, suivant le succĂšs du code durant la transaction.
Avertissement
PDO ne vérifie la possibilité d'utiliser des transactions qu'au niveau du pilote.
Si certaines conditions Ă l'exĂ©cution empĂȘchent les transactions de fonctionner,
PDO::beginTransaction() retournera tout de mĂȘme true
sans erreur si le serveur accepte de démarrer une transaction.
Un exemple serait d'utiliser des transactions sur des tables au format MyISAM
du serveur de base de données MySQL.
Avertissement
Commit implicite avec des déclarations DDL :
Certaines bases de données émettent automatiquement un
COMMIT implicite lorsqu'une déclaration de langage de définition de base de données (DDL),
telle que DROP TABLE ou CREATE TABLE,
est exécutée dans une transaction. Cela signifie que toutes les modifications précédentes effectuées dans la
mĂȘme transaction seront automatiquement validĂ©es et ne peuvent pas
ĂȘtre annulĂ©es.
MySQL et Oracle sont des exemples de bases de données qui
présentent ce comportement.
Exemple #1 Exemple de Commit implicite
<?php
$pdo->beginTransaction();
$pdo->exec("INSERT INTO users (name) VALUES ('Rasmus')");
$pdo->exec("CREATE TABLE test (id INT PRIMARY KEY)"); // Un COMMIT implicite se produit ici
$pdo->rollBack(); // Cela N'annulera PAS l'INSERT/CREATE pour MySQL ou Oracle
?>
Meilleure pratique : Ăvitez d'exĂ©cuter des dĂ©clarations DDL Ă l'intĂ©rieur des transactions
lors de l'utilisation des bases de données qui imposent ce comportement. Si nécessaire, séparez les opérations DDL
de la logique transactionnelle.
Lorsque le script se termine ou lorsque la connexion est sur le point de se fermer,
si l'on a une transaction en cours, PDO l'annulera automatiquement.
Ceci est une mesure de sécurité afin de garantir l'intégrité des données
dans le cas oĂč le script se termine d'une façon inattendue. Si on ne valide pas
explicitement la transaction, alors, on présume que quelque chose s'est mal passé
et l'annulation de la transaction intervient afin de garantir la sécurité des données.
Avertissement
L'annulation automatique intervient si l'on a initialisé la transaction via
PDO::beginTransaction(). Si l'on a manuellement
exĂ©cutĂ© une requĂȘte qui commence une transaction, PDO n'a aucun moyen de
le savoir et donc, n'annulera pas automatiquement cette transaction si quelque
chose s'est mal passé.
Exemple #2 Exécution d'un groupe dans une transaction
Dans l'exemple suivant, supposons que nous allons créer un jeu d'entrées
pour un nouvel employé, dont le numéro d'ID sera 23.
En plus des données de base sur cette personne, nous devons également
lui enregistrer son salaire. Il est trĂšs simple d'effectuer deux mises Ă jour
séparées, mais en les enfermant dans les appels des fonctions
PDO::beginTransaction() et
PDO::commit(), nous garantissons que personne
ne pourra voir ces modifications tant qu'elles ne seront pas complĂštes.
Si quelque chose tourne mal, le bloc de capture annulera toutes les
modifications effectuées depuis le début de la transaction et affichera
un message d'erreur.
<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true));
echo "Connecté\n";
} catch (Exception $e) {
die("Impossible de se connecter : " . $e->getMessage());
}
try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
$dbh->exec("insert into salarychange (id, amount, changedate)
values (23, 50000, NOW())");
$dbh->commit();
} catch (Exception $e) {
$dbh->rollBack();
echo "Ăchec : " . $e->getMessage();
}
?>
On n'est pas limités dans le nombre de mises à jour dans une transaction ;
il est Ă©galement possible d'y effectuer des requĂȘtes complexes et bien sĂ»r, utiliser
ces informations pour construire d'autres mises Ă jour et requĂȘtes ; durant l'activitĂ©
de la transaction, l'on est sûrs que personne d'autre ne peut effectuer des
modifications alors que l'on est au milieu des modifications.
Pour plus d'informations sur les transactions, se reporter Ă la documentation
fournie par la base de données.