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.

add a note

User Contributed Notes 4 notes

up
4
hooby404 at gmail dot com ¶
3 years ago
> You're not limited to making updates in a transaction; you can also issue complex 
> queries to extract data, and possibly use that information to build up more updates 
> and queries; while the transaction is active, you are guaranteed that no one else can 
> make changes while you are in the middle of your work. For further reading on 
> transactions, refer to the documentation provided by your database server. 

This only holds true if you specifically do "SELECT .... FOR UPDATE". 

Without the "FOR UPDATE" part, when two transactions run at the same time, the second transaction could change a value AFTER the first transaction read it, but BEFORE the first transaction used it for updates.

Without the "FOR UPDATE" part you are absolutely NOT GUARANTEED that no one else can make changes while you are in the middle of your work.
up
3
harl at gmail dot com ¶
8 years ago
Some DBMSs allow DDL (table creation/alteration) within transactions, some do not. Asking "Does my DBMS allow DDL within transactions without forcing a commit?" gives the following example answers:

CUBRID: Yes
DB2 UDB: Yes
Firebird: Yes
Informix: Yes
MySQL: No
Oracle: No (although schema upgrades can be rolled out using "edition-based redefinition")
PostgreSQL: Yes
SQLite: Yes
SQL Server: Sometimes, depending on isolation level, type of command, etc.
Sybase: Yes
up
3
pasamio at gmail dot com ¶
13 years ago
Typically data definition language clauses (DDL) will trigger the database engine to automatically commit:
http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html

Many other databases (e.g. Oracle) will implicitly commit before and after running DDL statements.
up
-1
toyu at hotmail dot com ¶
3 months ago
Last insert ID will not be rollbacked (MySQL InnoDB)