InnoDB表锁用于写入但允许读取

时间:2017-10-18 16:14:50

标签: php mysql mariadb innodb

我有一个表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)

}

我知道必须有更好,更聪明的解决方案,没有循环和睡眠。但我不知道使用哪一个。

1 个答案:

答案 0 :(得分:1)

如果您可以在lock_wait_timeout之内完成冗长的内容,默认为50秒,则使用BEGIN ... COMMIT。 (就个人而言,我会将其限制为2秒,而不是50秒。)

否则,设计一些其他方法 - 每个编写者都有一个表,表示你在这个“关键部分”中“忙”。它可能不需要比单行的1或2列表更多。

抓取该互斥锁时,请确保在事务中封装fetch,set等,并对失败做出反应。获得锁定后,继续做慢速的事情。最后释放锁。

警告:如果发生崩溃或软件错误,则可能永远不会执行释放锁定的代码。因此,最好包含一个时间戳,加上一些注意到互斥锁还没有在“很长”的时间内发布的东西。他们可以通过电子邮件向您发送问题并清除锁定。