【发布时间】: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 发送他们的请求。