PHP Australia Conference 2015

Transactions

The current version of the plugin is not transaction safe, 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 must use SQL hints to work around this limitation.

Example #1 Plugin config with one slave and one master

[myapp]
master[]=localhost:/tmp/mysql.sock
slave[]=192.168.2.27:3306

Example #2 Using SQL hints for transactions

<?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.3.99 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.3.99, API calls to set the autocommit mode and setting the experimental 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 is done to prevent connection switches in the middle of a transaction. Once autocommit gets enabled again, the plugin starts to load balance statements again.

Example #3 Experimental trx_stickiness setting

[myapp]
master[]=localhost:/tmp/mysql.sock
slave[]=192.168.2.27:3306
trx_stickiness=master

Example #4 Outlook: transaction aware

<?php
if (version_compare(PHP_VERSION"5.3.99""<"))
  die(
"This feature requires PHP 5.3.99, you are using " PHP_VERSION);
  
$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();
?>

Note:

The plugin configuration option trx_stickiness=master is an experimental feature. It requires PHP 5.3.99.

add a note add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top