53
XA/Distributed Transactions
392
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
/* run queries as usual: XA BEGIN will be injected upon running a query */
if (!$mysqli->query("INSERT INTO orders(order_id, item) VALUES (1, 'christmas tree, 1.8m')")) {
/* Either INSERT failed or the injected XA BEGIN failed */
if ('XA' == substr($mysqli->sqlstate, 0, 2)) {
printf("Global transaction/XA related failure, [%d] %s\n", $mysqli->errno, $mysqli->error);
} else {
printf("INSERT failed, [%d] %s\n", $mysqli->errno, $mysqli->error);
}
/* rollback global transaction */
mysqlnd_ms_xa_rollback($mysqli, $xid);
die("Stopping.");
}
/* continue carrying out queries on other servers, e.g. other shards */
/* commit the global transaction */
if (!mysqlnd_ms_xa_commit($mysqli, $xa_id)) {
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
}
?>
Unlike with local transactions, which are carried out on a single server, XA transactions have an identifier
(xid) associated with them. The XA transaction identifier is composed of a global transaction identifier
(gtrid), a branch qualifier (bqual) a format identifier (formatID). Only the global transaction identifier can and
must be given when calling any of the plugins XA functions.
Once a global transaction has been started, the plugin begins tracking servers until the global transaction
ends. When a server is picked for query execution, the plugin injects the SQL statement XA BEGIN
prior to executing the actual SQL statement on the server. XA BEGIN makes the server participate in
the global transaction. If the injected SQL statement fails, the plugin will report the issue in reply to the
query execution function that was used. In the above example, $mysqli->query("INSERT INTO
orders(order_id, item) VALUES (1, 'christmas tree, 1.8m')") would indicate such an
error. You may want to check the errors SQL state code to determine whether the actual query (here:
INSERT) has failed or the error is related to the global transaction. It is up to you to ignore the failure to
start the global transaction on a server and continue execution without having the server participate in the
global transaction.
Example 7.19 Local and global transactions are mutually exclusive
<?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()));
}
/* start a local transaction */
if (!$mysqli->begin_transaction()) {
die(sprintf("[%d/%s] %s\n", $mysqli->errno, $mysqli->sqlstate, $mysqli->error));
}
/* cannot start global transaction now - must end local transaction first */
$gtrid_id = "12345";
if (!mysqlnd_ms_xa_begin($mysqli, $gtrid_id)) {
die(sprintf("[%d/%s] %s\n", $mysqli->errno, $mysqli->sqlstate, $mysqli->error));
}
?>