如何实现基于数据库锁定的防止重复的保护

问题描述:

在使用InnoDB存储引擎的Web应用程序中,我无法在以下情况下充分利用数据库锁定。如何实现基于数据库锁定的防止重复的保护

有3个表格,我会称它们为aa,arai

aa拥有基本记录,让我们说文章。 ar保存与每个aa记录有关的信息,并且aaar之间的关系是1:m

ar的记录存储在aa的记录被读取时第一次被存储。问题是当两个请求在(几乎)相同时从aa(它还没有将其相关记录存储在ar中)读取记录时发起,ar记录被复制。

下面是一个伪代码,以帮助了解情况:

  • 阅读要求aa记录。

  • 扫描ar表以确定给定的aa记录是否已存储任何内容。 (假设它没有。)

  • 请参阅ai以便找出在给定的aa记录中要存储在ar中的内容。 (ai似乎有点风马牛不相及,但我发现它也有参与锁定...可能是错误的。)

  • 插入几行ar

这里是我想达到的目标:

  • 阅读请求的aa记录。

使用或不使用交易,LOCK ar,所以任何后续请求试图读取ar将等待AT这一点直到这个顺序完成。

  • 扫描ar表,以发现如果给定aa记录已经存储了什么。 (假设它没有。)问题是,如果有两个同时发生的请求,两个发现对于给定的aa记录在ar中没有记录,并且它们都继续插入相同的行两次。否则,如果存在,则会中断此序列并且不会发生INSERT。

  • 咨询ai为了找出在给定的aa记录中要存储在ar中的内容。 (ai似乎有点不相关,但我发现它也必须参与锁定...可能是错误的。)

  • 插入几行ar

解除锁定ON ar

似乎很简单,我是在避免重复失败。我正在测试Bash shell中一个简单命令的同时请求(使用wget)。

我已经花了一段时间学习如何锁定InnoDB引擎在这里http://dev.mysql.com/doc/refman/5.5/en/innodb-lock-modes.html和这里http://dev.mysql.com/doc/refman/5.5/en/innodb-locking-reads.html如何工作,并尝试了几种方法来利用锁,仍然没有运气。

我希望整个ar表被锁定(因为我想阻止来自多个请求的INSERT发生)导致进一步尝试与此表交互以等待,直到第一个锁被释放。但是只有一处提到“整个表”被锁定在文档中(第一个链接页面中的“意图锁定”部分),但没有进一步讨论,或者我无法知道如何实现它。

任何人都可以指出正确的方向吗?

SET tx_isolation='READ-COMMITTED'; 
START TRANSACTION; 
SELECT * FROM aa WHERE id = 1234 FOR UPDATE; 

这确保了一次只有一个线程可以访问aa中的给定行。根本不需要锁定ar表,因为任何其他想要访问行1234的线程都将等待。

然后查询ar以找出相应的aa存在哪些行,并决定是否要插入更多行到ar

请记住,aa中的行仍处于锁定状态。因此,快速完成工作,成为一名优秀的公民,迅速做出承诺。

COMMIT; 

这允许下一个等待同一行aa的线程继续进行。通过使用READ-COMMITTED,它将能够在ar中看到刚提交的新行。

+0

感谢您的提示,并看似亲水平的答复。我马上给它一下,如果它有效,就更新你。 – marekful 2014-10-16 20:00:10

+0

当然(虽然问题已经太长了),但真实的生活情况要复杂得多,而且在请求过程中涉及许多其他查询。到目前为止,我遇到了'一般错误:2014无法执行查询,而其他未缓冲的查询处于活动状态',但不会放弃,这似乎是要走的路。 – marekful 2014-10-16 20:15:33

+1

@MarcellFülöp,你可能喜欢阅读我的回答[MySQL的错误原因2014无法执行查询,而其他未缓冲的查询处于活动状态](http://stackoverflow.com/questions/17434102/causes-of-mysql-error-2014 -cannot-execute-queries-while-other-unbuffered-queries/17582620#17582620) – 2014-10-16 21:47:52