La versión actual del complemento no es segura con transacciones de forma predeterminada, ya que no considera su ejecución en ningún caso. Las transacciones SQL son unidades de trabajo para ejecutarlas en un único servidor. El complemento no siempre sabe cuándo comienza y cuándo finaliza una unidad de trabajo. Por lo tanto, el complemento podría decidir intercambiar conexiones en mitad de una transacción.
Ningún tipo de equilibrador de carga de MySQL puede detectar los límites de una transacción sin ningún tipo de sugerencia por parte de la aplicación.
Se pueden usar sugerencias SQL para superar esta limitación. De forma alternativa, se puede activar la monitorización de llamadas a la API de transacciones. En el último caso, de deben usar llamadas a la API solamente para controlar transacciones. Véase más abajo.
Ejemplo #1 Configuración del complemento con un esclavo y un maestro
[myapp] { "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } } }
Ejemplo #2 Usar sugerencias SQL para transacciones
<?php
$mysqli = new mysqli("myapp", "nombre_usuario", "contraseña", "base_datos");
if (!$mysqli) {
/* Por supuesto, su manejo de errores es mejor... */
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
}
/* No es un SELECT, se usará el maestro */
if (!$mysqli->query("START TRANSACTION")) {
/* Por favor, use un manejo de errores mejor en su código */
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
/* ¡Evitar el intercambio de conexión! */
if (!$mysqli->query(sprintf("/*%s*/INSERT INTO test(id) VALUES (1)", MYSQLND_MS_LAST_USED_SWITCH))) {
/* Por favor, realice el ROLLBACK apropiado en su código, y no use simplemente '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))) {
$fila = $res->fetch_assoc();
$res->close();
if ($fila['_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();
?>
Desde PHP 5.4.0, la biblioteca mysqlnd
permite al
complemento monitorizar el estado del modo autocommit
, si
el modo está establecido por llamadas a la API en lugar de usar sentencias SQL como
SET AUTOCOMMIT=0
. Esto permite que el complemento
considere las transacciones. En este caso, es necesario usar sugerencias SQL.
Si se está utlizando PHP 5.4.0 o superior, con las llamadas a la API que habilitan el modo autocommit
,
y cuando se establece la opción de configuración del complemento
trx_stickiness=master,
éste puede deshabilitar automáticamente el equilibrado de carga y el intercambio de conexiones
para transacciones SQL. Con esta configuración, el complemento detiene el equilibrado de carga
si autocommit
está deshabilitado, y dirige todas las sentencias al
maestro. Esto evita el intercambio de conexiones en mitad de
una transacción. Una vez que autocommit
es rehabilitado, el complemento
inicia de nuevo las sentencias con equilibrado de carga.
La detección de los límites de transacciones basada en API ha sido mejorada con PHP 5.5.0 y
PECL/mysqlnd_ms
1.5.0 para cubirir no solo llamadas a mysqli_autocommit(),
sino también a mysqli_begin(),
mysqli_commit() y mysqli_rollback().
Ejemplo #3 Equilibrado de carga considerando transacciones: el ajuste 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" } }
Ejemplo #4 Consideración de transacciones
<?php
$mysqli = new mysqli("myapp", "nombre_usuario", "contraseña", "base_datos");
if (!$mysqli) {
/* Por supuesto, su manejo de errores es mejor... */
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
}
/* Deshabilitar autocommit, el complemento ejecutará todas las sentencias en el maestro */
$mysqli->autocommit(FALSE);
if (!$mysqli->query("INSERT INTO test(id) VALUES (1)")) {
/* Por favor, realice el ROLLBACK apropiado en su código, y no use simplemente 'die' */
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
if ($res = $mysqli->query("SELECT COUNT(*) AS _num FROM test")) {
$fila = $res->fetch_assoc();
$res->close();
if ($fila['_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));
}
/* El complemento asume que la transacción ha finalizado e inicia el equilibrado de carga de nuevo */
$mysqli->autocommit(true);
$mysqli->close();
?>
Nota: Requisitos de versión
La opción de configuración del complemento trx_stickiness=master requiere PHP 5.4.0 o superior.
Por favor, observe las restricciones descritas en la sección de conceptos sobre manejo de transacciones.