Mysql:如何在事务期间锁定整个表?

时间:2018-03-12 10:30:22

标签: php mysql sql transactions

我有这样的交易(innoDB):

START TRANSACTION;
SELECT 1 FROM test WHERE id > 5; // Let's assume this returns 0 rows

// Some very long operation here

//If the previous SELECT contained 0 results, this Insert will be executed
INSERT INTO test VALUES...;
COMMIT;

现在的问题是,如果更多的会话同时执行,那么它们都将最终执行INSERT,因为当这些会话中的长任务完成时,所有的会话有足够的时间来执行SELECT,并且它将为所有这些返回0行结果,因为INSERT由于长任务运行而尚未执行。

所以基本上,在执行START TRANSACTION之后,我需要以某种方式锁定整个表test(因此它不能被其他会话读取并且他们将被迫等待),但我不知道如何,因为我不能使用LOCK TABLES test查询,因为COMMITs我已经开始的事务。 我也不能使用SELECT .. FOR UPDATE,因为这只会阻止现有的行被修改,但它不会阻止插入新的行。

1 个答案:

答案 0 :(得分:0)

如果您有一些只需要运行一次的长时间运行的任务,请在单独的表中设置一个标志,表示该任务已经启动,并检查 而不是写入目标表的行数,以便该服务的另一个实例不会两次启动该作业。

这样做的另一个好处是,您不会依赖任务的细节来了解它的状态(因此,如果任务的性质发生变化,其他代码的完整性就不会出现问题。 ; t崩溃),你并没有试图通过做一些像锁定整个桌子这样糟糕的事情来解决这个问题。使用交易的一个要点是没有必要锁定所有内容(虽然当然可以使用不同的隔离级别,但这不是讨论的主题)。

然后在任务的最后一位完成时将标志设置为false。