我正在尝试在运行一些代码时锁定一些表,并在完成后解锁表.

处理:

>运行锁定表MySQL查询.

>运行一些PHP代码.

>运行解锁表MySQL查询.

在运行此过程时,10次中的9次运行完美.有时,当我运行我的查询时,MySQL没有响应,PHP只是等待响应.由于没有响应发生,我从未进入步骤2或3,表格无限期保持锁定状态.我在每次尝试中都运行完全相同的锁表查询.

经过一些研究,我发现问题发生在第二台服务器写入数据库然后第一台服务器尝试执行“LOCK TABLES”查询时.似乎第二台服务器的写入执行“元数据锁定”.我相信这是由于MySQL启用了“自动提交”功能并且事务尚未完成.因此,当我试图锁定表时,MySQL永远不会响应并显示“show processlist;”在我手动终止进程之前,已经列出了“等待表元数据锁定| LOCK TABLES …”.

我锁定了许多表格.下面是我的实际表查询的类似示例.我根据我试图阻止访问表的查询多次使用同一个表和不同的别名.

$sql = "LOCK TABLES table1 as t1 WRITE
, table2 as t2 WRITE
, table3 WRITE
, table2 WRITE
, table4 WRITE
, table1 WRITE
, table5 WRITE
, table5 as t5 WRITE
, table6 as t6 WRITE
, table7 as t7 WRITE
, table7 WRITE
, table8 as t8 WRITE
, table9 t9 WRITE
, table10 t10 WRITE
, table11 t11 WRITE
, table12 WRITE;";
$this->mysqli = new mysqli(
$this->credentials->server
, $this->credentials->user
, $this->credentials->password
, $this->credentials->database
);
try{
error_log('before first attempt lock tables '.$sql);
$this->mysqli->query($sql);
error_log('after first attempt lock tables');
} catch (Exception $e){
error_log('Error locking tables: '.$e->getMessage());
}
error_log('After try catch.');
if($this->mysqli->error){
error_log('lock table error: '.$this->mysqli->error);
}

当进程失败时,我在PHP错误日志中看到“在第一次尝试锁定表之前”.我没有看到任何其他error_log()调用.经过一番检查后,我确定这是因为PHP没有收到MySQL的回复.

我从未进入Catch异常,因为MySQL没有返回错误.除非我手动终止MySQL锁表进程,否则MySQL不会返回任何内容.

如果我不杀死进程,PHP代码永远不会停止等待来自mysql的响应.

我很困惑为什么“LOCK TABLES”查询没有优雅地等待“元数据锁”完成然后运行.据我所知,允许多个服务器写入数据库,锁表功能可以一起工作而不是无限期挂起.

解决方法:

插科打诨!如果您使用ENGINE = InnoDB,则基本上不需要LOCK TABLES.如果您仍在使用MyISAM,请转换!

转换后,您需要了解如何将事物放入“事务”(BEGIN … COMMIT)并使用SELECT … FOR UPDATE.