我有一个表COMMANDS
,用户可以同时插入数据。
每次插入后,我必须进行一些(耗时的)计算,并将结果保存到另一个表RESULTS
。
同时所有用户也从COMMANDS
读取数据。
我的问题是:
在插入新$command
之后,我在计算中使用该表中的所有行。每一行都会影响计算,也可能会影响之前的$commands
,因为我希望锁定此表以进行新的插入,直到进行当前计算并保存结果。但我也不想阻止其他用户查看COMMANDS
的当前状态。
我很想锁定一张桌子进行书写而不会锁定阅读。
我正在使用InnoDB引擎。我读了一些关于锁定的文件,但我完全糊涂了。
共享和排他锁,意图锁,间隙锁...
这似乎很愚蠢,但目前我正在使用下面的机制
public function storeNewCommand($command){
// $busy_flag is an app level global that can be read by all user sessions
if($busy_flag){
usleep(10000);
return $this->storeNewCommand($command);
}
$busy_flag = true; //(lock)
/*
...insert new $command to COMMANDS
...do calculations using all comands including last one
...store results in RESULTS
*/
$busy_flag = false; //(unlock)
}
我知道必须有更好,更聪明的解决方案,没有循环和睡眠。但我不知道使用哪一个。
答案 0 :(得分:1)
如果您可以在lock_wait_timeout
之内完成冗长的内容,默认为50秒,则使用BEGIN
... COMMIT
。 (就个人而言,我会将其限制为2秒,而不是50秒。)
否则,设计一些其他方法 - 每个编写者都有一个表,表示你在这个“关键部分”中“忙”。它可能不需要比单行的1或2列表更多。
抓取该互斥锁时,请确保在事务中封装fetch,set等,并对失败做出反应。获得锁定后,继续做慢速的事情。最后释放锁。
警告:如果发生崩溃或软件错误,则可能永远不会执行释放锁定的代码。因此,最好包含一个时间戳,加上一些注意到互斥锁还没有在“很长”的时间内发布的东西。他们可以通过电子邮件向您发送问题并清除锁定。