在使用InnoDB存储引擎的Web应用程序中,我无法在以下场景中充分利用数据库锁定。
有3个表格,我会称之为aa
,ar
和ai
。
aa
保存基本记录,让我们说文章。 ar
包含与每个aa
记录相关的信息,aa
和ar
之间的关系为1:m
。
ar
中的记录在第一次首次读取aa
的记录时存储。问题是当两个请求(几乎)相同时从aa
读取记录(其ar
中尚未存储其相关记录)时,ar
记录是重复的。
这是一个有助于了解情况的伪代码:
阅读请求的aa
记录。
扫描ar
表以查明给定的aa
记录是否已存储任何内容。 (假设没有。)
请参阅ai
,以了解ar
对于给定的aa
记录要存储的内容。 (ai
似乎有点无关紧要,但我发现它也必须参与锁定......可能是错误的。)
在ar
这是我想要实现的目标:
aa
记录。有或没有使用交易,锁定ar
,所以任何后续请求都要在ar
之前阅读,在这一点完成之前等待这一点。
扫描ar
表以查明给定的aa
记录是否已存储任何内容。 (假设它没有。)问题是,在两个同时发出的请求的情况下,两者都发现ar
中没有给定aa
记录的记录,并且它们都继续插入相同的行两次。否则,如果有,则此序列被中断且不会发生INSERT。
请参阅ai
,以了解ar
对于给定的aa
记录要存储的内容。 (ai
似乎有点无关紧要,但我发现它也必须参与锁定......可能是错误的。)
在ar
释放ar
看起来很简单,我没有成功避免重复。我正在测试来自Bash shell中的简单命令的同时请求(使用wget)。
我花了一段时间来学习如何使用InnoDB引擎({3}}和http://dev.mysql.com/doc/refman/5.5/en/innodb-lock-modes.html完全锁定,并尝试了几种方法来使用锁,但仍然没有运气。
我希望整个ar
表被锁定(因为我想阻止INSERT发生多个请求)导致进一步尝试与此表交互以等到第一个锁被释放。但是,只有一个提及"整个表"被锁定在文档中(第一个链接页面中的Intention Locks部分),但没有进一步讨论,或者我无法确定如何实现它。
有人能指出正确的方向吗?
答案 0 :(得分:1)
SET tx_isolation='READ-COMMITTED';
START TRANSACTION;
SELECT * FROM aa WHERE id = 1234 FOR UPDATE;
这确保了一次只有一个线程可以访问aa
中的给定行。根本不需要锁定ar
表,因为任何其他可能想要访问第1234行的线程都会等待。
然后查询ar
以找出相应aa
的存在行,并决定是否要向ar
插入更多行。
请记住,aa
中的行仍处于锁定状态。因此,通过快速完成工作成为一个好公民,并立即进行COMMIT。
COMMIT;
这允许等待同一行aa
的下一个线程继续进行。使用READ-COMMITTED
,它将能够在ar
中看到刚刚提交的新行。