Transactions locales
La version actuelle du plugin ne gère pas les transactions de façon sûre par défaut, car il n'est pas sûre d'exécuter des transactions dans tous les cas. Les transactions SQL sont des opérations atomiques exécutées sur un seul et même serveur. Le plugin ne sait pas toujours quand l'opération atomique commence et quand elle prend fin. Ainsi, il peut décider de basculer de connexion au milieu d'une transaction.
Aucun type de balance de charge MySQL peut détecter les limites d'une transaction sans avoir d'astuce au sein de l'application.
Vous devez utiliser des astuces SQL pour éviter un tel comportement, ou activer la surveillance des appels de transaction à l'API. Dans ce cas, vous devez utiliser des appels à l'API pour contrôler les transactions, voyez ci-après.
Exemple #1 Configuration du plugin avec un esclave et un maitre
[myapp] { "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } } }
Exemple #2 Utilisation des astuces SQL pour les transactions
<?php
$mysqli = new mysqli("myapp", "username", "password", "database");
if (!$mysqli) {
/* Evidemment, votre propre gestion des erreurs serait meilleure... */
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
}
/* Pas un SELECT, utilisera le maitre */
if (!$mysqli->query("START TRANSACTION")) {
/* Evidemment, votre propre gestion des erreurs serait meilleure */
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
/* Empêche le changement de connexion! */
if (!$mysqli->query(sprintf("/*%s*/INSERT INTO test(id) VALUES (1)", MYSQLND_MS_LAST_USED_SWITCH)))) {
/* Utilisez un ROLLBACK dans votre code, pas juste un die() */
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
if ($res = $mysqli->query(sprintf("/*%s*/SELECT COUNT(*) AS _num FROM test", MYSQLND_MS_LAST_USED_SWITCH)))) {
$row = $res->fetch_assoc();
$res->close();
if ($row['_num'] > 1000) {
if (!$mysqli->query(sprintf("/*%s*/INSERT INTO events(task) VALUES ('cleanup')", MYSQLND_MS_LAST_USED_SWITCH))) {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
}
} else {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
if (!$mysqli->query(sprintf("/*%s*/UPDATE log SET last_update = NOW()", MYSQLND_MS_LAST_USED_SWITCH)))) {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
if (!$mysqli->query(sprintf("/*%s*/COMMIT", MYSQLND_MS_LAST_USED_SWITCH)))) {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
$mysqli->close();
?>
Depuis PHP 5.4.0 la bibliothèque mysqlnd permet au plugin de surveiller le statut de l'autocommit, si celui-ci est utilisé via des appels à l'API plutot que via une requête du type SET AUTOCOMMIT=0. Ceci rend le plugin sensible et réactif aux transactions. Dans ce cas, vous n'avez pas besoin d'utiliser d'astuces SQL.
Si vous utilisez PHP 5.4.0, les appels de l'API pour gérer l'autocommit et le paramètre trx_stickiness=master permettent au plugin de désactiver l'équilibrage de charge et la bascule entre les connexions si autocommit est désactivé, et de diriger les requêtes vers le maitre. Ceci évite la bascule de connexion au milieu d'une transaction. Une fois que autocommit est réactivé, le plugin reprend l'équilibrage de charge.
La détecttion des limites d'une transaction en se basant que l'API a été améliorée avec PHP 5.5.0 et PECL/mysqlnd_ms 1.5.0 pour couvrir non seulement les appels à mysqli_autocommit() mais aussi à mysqli_begin(), mysqli_commit() et mysqli_rollback().
Exemple #3 Le paramètre trx_stickiness
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "127.0.0.1", "port": "3306" } }, "trx_stickiness": "master" } }
Exemple #4 Gestion propre des transactions
<?php
$mysqli = new mysqli("myapp", "username", "password", "database");
if (!$mysqli) {
/* Evidemment, votre propre gestion des erreurs serait meilleure... */
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
}
/* Désactive autocommit, le plugin utilisera le maitre pour toutes les requêtes */
$mysqli->autocommit(FALSE);
if (!$mysqli->query("INSERT INTO test(id) VALUES (1)")) {
/* Utilisez un ROLLBACK dans votre code, pas juste un die() */
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
if ($res = $mysqli->query("SELECT COUNT(*) AS _num FROM test")) {
$row = $res->fetch_assoc();
$res->close();
if ($row['_num'] > 1000) {
if (!$mysqli->query("INSERT INTO events(task) VALUES ('cleanup')")) {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
}
} else {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
if (!$mysqli->query("UPDATE log SET last_update = NOW()")) {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
if (!$mysqli->commit()) {
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
/* Le plugin sait que la trasaction est terminée, il reprend l'équilibrage de charge */
$mysqli->autocommit(TRUE);
$mysqli->close();
?>
Note: Versions requises
La directive de configuration du plugin trx_stickiness=master requiert PHP 5.4.0 ou plus récent.
Veuillez également prendre en compte les restrictions abordées dans la section sur les concepts de gestion des transactions.
Document créé le 30/01/2003, dernière modification le 26/10/2018
Source du document imprimé : https://www.gaudry.be/php-rf-mysqlnd-ms.quickstart.transactions.html
L'infobrol est un site personnel dont le contenu n'engage que moi. Le texte est mis à disposition sous licence CreativeCommons(BY-NC-SA). Plus d'info sur les conditions d'utilisation et sur l'auteur.
Références
Ces références et liens indiquent des documents consultés lors de la rédaction de cette page, ou qui peuvent apporter un complément d'information, mais les auteurs de ces sources ne peuvent être tenus responsables du contenu de cette page.
L'auteur de ce site est seul responsable de la manière dont sont présentés ici les différents concepts, et des libertés qui sont prises avec les ouvrages de référence. N'oubliez pas que vous devez croiser les informations de sources multiples afin de diminuer les risques d'erreurs.