【问题标题】:InnoDB table lock for writing but allow readingInnoDB 表锁用于写入但允许读取
【发布时间】:2017-10-18 16:14:49
【问题描述】:

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

}

我知道必须有更好、更聪明的解决方案来解决这个问题,而无需循环和休眠。但我不知道该用哪一个。

【问题讨论】:

  • 注意如何设置队列,这样可以将“用户输入进程”与“存入数据库进程”分开,控制计算时如何避免插入新行。
  • 谢谢@Alfabravo 我正在使用一些队列作业,但它们是异步工作的,每次插入后所有已保存命令的当前状态对我来说非常重要。因此,如果正在进行计算,我想在数据库级别阻止插入。
  • 对我来说,模拟表级锁是错误的策略。不管有多少用户,他们都应该通过同一个队列和同一个 DAO 发送他们的请求。

标签: php mysql mariadb innodb


【解决方案1】:

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

否则,设计一些其他方法——有一个每个作家都尊重的表格,表明你在这个“关键部分”中“忙碌”。它可能不需要比单行的 1 或 2 列表多得多。

获取该互斥体时,请务必将获取、设置等内容封装在事务中并对失败做出反应。获得锁后,然后继续做缓慢的事情。最后释放锁。

警告:如果出现崩溃或软件错误,释放锁的代码可能永远不会执行。因此,最好包含一个时间戳,以及一些需要注意的事项,即互斥锁在“长时间”内没有被释放。他们可以通过电子邮件向您发送有关问题的电子邮件并清除锁定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多