©
This document uses PHP Chinese website manual Release
当前版本的插件并不是事务安全的,因为他并没有识别全部的事务操作。 SQL 事务单元是在单一服务器中运行的。插件并不能有效的知道事务单元 何时开始,何时终止。所以,在事务单元中,可能数据库连接会被切换。
如果应用没有设定事务单元编辑,那么没有任何 MySQL 负载均衡能够检测他。
可以通过 SQL hints 来解除这个限制。可以选择性的调用事务 API 进行监控, 然后嗲用 API 执行控制事务。下面给出范例:
Example #1 配置一个 master 和一个 slave 的插件
[myapp] { "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "192.168.2.27", "port": "3306" } } } }
Example #2 在事务中使用 SQL hints
<?php
$mysqli = new mysqli ( "myapp" , "username" , "password" , "database" );
if (! $mysqli )
die( sprintf ( "[%d] %s\n" , mysqli_connect_errno (), mysqli_connect_error ()));
if (! $mysqli -> query ( "START TRANSACTION" )) {
die( sprintf ( "[%d] %s\n" , $mysqli -> errno , $mysqli -> error ));
}
if (! $mysqli -> query ( sprintf ( "INSERT INTO test(id) VALUES (1)" , MYSQLND_MS_LAST_USED_SWITCH )))) {
die( sprintf ( "[%d] %s\n" , $mysqli -> errno , $mysqli -> error ));
}
if ( $res = $mysqli -> query ( sprintf ( "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 ( "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 ( "UPDATE log SET last_update = NOW()" , MYSQLND_MS_LAST_USED_SWITCH )))) {
die( sprintf ( "[%d] %s\n" , $mysqli -> errno , $mysqli -> error ));
}
if (! $mysqli -> query ( sprintf ( "COMMIT" , MYSQLND_MS_LAST_USED_SWITCH )))) {
die( sprintf ( "[%d] %s\n" , $mysqli -> errno , $mysqli -> error ));
}
$mysqli -> close ();
?>
自从 PHP 5.4.0 版本开始,mysqlnd library 允许插件监控 autocommit 模式下的状态,例如调用 SET AUTOCOMMIT=0 这样的语句,这将让插件开始关心事务处理。这样你就可以不用使用 SQl hints。
从 PHP 5.4.0 版本开始,调用 API autocommit 模式,插件设定中有 trx_stickiness=master, 那么插件将在事务中自动禁止负载均衡和连接切换。在 autocommit 禁用的配置当中, 插件将在事务过程中将所有的语句发送给 master,禁用负载均衡。当 autocommit 重新启用以后,插件将重新开始负载均衡所有的语句。
在 PHP 5.5.0 和 PECL/mysqlnd_ms 1.5.0 版本后,这种检查将不仅仅检查 mysqli_autocommit() 还会检查 mysql_commit() 和 mysql_rollback() 。
Example #3 事务相关负载均衡下的 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" } }
Example #4 Transaction aware
<?php
$mysqli = new mysqli ( "myapp" , "username" , "password" , "database" );
if (! $mysqli )
die( sprintf ( "[%d] %s\n" , mysqli_connect_errno (), mysqli_connect_error ()));
$mysqli -> autocommit ( FALSE );
if (! $mysqli -> query ( "INSERT INTO test(id) VALUES (1)" )) {
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 ));
}
$mysqli -> autocommit ( TRUE );
$mysqli -> close ();
?>
Note: 版本需求
trx_stickiness=master 参数需要 PHP 5.4.0 以上版本。
可以参考相关限制在 transaction handling 章节中。