MySQL InnoDB插入并选择锁定

时间:2015-03-03 07:36:29

标签: php mysql

我创建了一个票务系统,它以最简单的形式记录加入队列的用户,并打印出带有队列号的票证。

当用户按下故障单时,数据库中会发生以下情况

INSERT details INTO All_Transactions_Table
SELECT COUNT(*) as ticketNum FROM All_Transactions_Table WHERE date is TODAY

在大多数情况下,这对我很有帮助。但是,我最近开始看到一些重复的票号。即使在我自己多次运行Web服务之后,我似乎无法复制该问题。

我猜测它是如何发生的,在某些情况下,INSERT仅发生在 AFTER SELECT COUNT之后。但这是一个InnoDB表,我没有使用INSERT DELAYED。 InnoDB是否有任何这样的隐含机制?

1 个答案:

答案 0 :(得分:1)

我认为你的问题是你有竞争条件。想象一下,你有两个人来买票。这是第一个人:

INSERT details INTO All_Transactions_Table

然后,在SELECT COUNT(*)发生之前,第二个人出现并且确实:

INSERT details INTO All_Transactions_Table

现在两个用户都获得相同的票号。这可能很难使用现有代码进行复制,因为它取决于使用MySQL的线程的确切调度,这完全超出了您的控制范围。

最好的解决方案是使用某种AUTO_INCREMENT列来提供票号,但如果失败,你可以使用交易来达到你想要的目的:

START TRANSACTION
SELECT COUNT(*) + 1 as ticketNum FROM All_Transactions_Table WHERE date is TODAY FOR UPDATE
INSERT details INTO All_Transactions_Table
COMMIT

但是,这是否有效将取决于您设置的事务隔离级别,并且效率不高。