The current version of the plugin is not transaction safe by default,
because it is not transaction aware. SQL transactions are
units of work to be run on a single server.
The plugin does not know when the unit of work starts and when it ends.
Therefore, the plugin may decide to switch connections in the middle
of a transaction.
You can either use SQL hints to work around this limitation. Alternatively,
you can activate transaction API call monitoring. In the latter case you
must use API calls only to control transactins, see below.
Пример #1 Plugin config with one slave and one master
<?php $mysqli = new mysqli("myapp", "username", "password", "database"); if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
/* Not a SELECT, will use master */ if (!$mysqli->query("START TRANSACTION")) { /* Please use better error handling in your code */ die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); }
/* Prevent connection switch! */ if (!$mysqli->query(sprintf("/*%s*/INSERT INTO test(id) VALUES (1)", MYSQLND_MS_LAST_USED_SWITCH)))) { /* Please do proper ROLLBACK in your code, don't just 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(); ?>
Starting with PHP 5.4.0, the mysqlnd library allows the
plugin to monitor the status of the autocommit mode, if
the mode is set by API calls instead of using SQL statements such as
SET AUTOCOMMIT=0. This makes it possible for the plugin to
become transaction aware.
If using PHP 5.4.0 or newer, API calls that enable autocommit mode,
and when setting the plugin configuration option
trx_stickiness=master,
the plugin can automatically disable load balancing and connection switches
for SQL transactions. In this configuration, the plugin stops load balancing
if autocommit is disabled and directs all statements to
the master. This prevents connection switches in the middle of
a transaction. Once autocommit is re-enabled, the plugin
starts to load balance statements again.
Пример #3 Transaction aware load balancing: trx_stickiness setting
<?php $mysqli = new mysqli("myapp", "username", "password", "database"); if (!$mysqli) /* Of course, your error handling is nicer... */ die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
/* Disable autocommit, plugin will run all statements on the master */ $mysqli->autocommit(FALSE);
if (!$mysqli->query("INSERT INTO test(id) VALUES (1)")) { /* Please do proper ROLLBACK in your code, don't just 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)); }
/* Plugin assumes that the transaction has ended and starts load balancing again */ $mysqli->autocommit(TRUE); $mysqli->close(); ?>