InnoDB表写锁,但允许读取
问题描述:
我有一个表COMMANDS
,用户同时插入数据。InnoDB表写锁,但允许读取
每插入一次,我必须做一些(耗时)的计算并将结果保存到另一个表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)
}
我知道必须有更好的和聪明的解决方案的机制这没有圈和睡觉。但我不知道使用哪一个。
答
如果你可以做的长度小于lock_wait_timeout
,其中默认为50秒,然后使用BEGIN
... COMMIT
。 (个人而言,我将其限制为更像2秒,而不是50)。
否则,设计一些其他方法 - 有一个表,每作家荣誉,说你在这个“关键”部分”。它可能不需要比具有单行的1列或2列表格多得多。
当抓取该互斥锁时,一定要将提取,设置等封装在一个事务中,并对失败作出反应。获得锁定后,继续执行缓慢的操作。最后放开锁。
警告:如果发生崩溃或软件错误,释放锁的代码可能永远不会执行。因此,包含时间戳以及注意互斥体在“很长”时间内未被释放的情况是很好的。他们可以通过电子邮件向您发送有关问题并清除锁定的信息
注意如何设置一个队列,这样就可以将“用户输入过程”从“保存到数据库过程”中分离出来,并控制如何在计算时避免插入新行。 – Alfabravo
谢谢@Alfabravo我正在使用一些队列作业,但他们工作异步,并且对每个插入后的所有保存的命令的当前状态非常重要。所以我想在数据库级别阻塞插入,如果有一个ongoning计算。 – Jaxovee
对我来说,模仿一个表级锁是错误的策略。不管用户如何,他们都应该通过相同的队列和相同的DAO发送他们的请求。 – Alfabravo