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

Mysql 如何实现基于数据库锁定的防重复保护,mysql,innodb,database-locking,Mysql,Innodb,Database Locking,在使用InnoDB存储引擎的web应用程序中,我无法在以下场景中充分利用数据库锁定 有3个表,我将它们称为aa,ar和ai aa保存基本记录,比如文章ar保存与每个aa记录相关的信息,aa和ar之间的关系是1:m 首次读取aa中的记录时,存储ar中的记录。问题在于,当两个请求在(几乎)相同的位置启动以从aa读取一条记录(该记录尚未在ar中存储其相关记录)时,ar记录重复 下面是一段伪代码,有助于理解这种情况: 读取请求的aa记录 扫描ar表,查看给定的aa记录是否已存储任何内容。(假设没有。)

在使用InnoDB存储引擎的web应用程序中,我无法在以下场景中充分利用数据库锁定

有3个表,我将它们称为
aa
ar
ai

aa
保存基本记录,比如文章
ar
保存与每个
aa
记录相关的信息,
aa
ar
之间的关系是
1:m

首次读取
aa
中的记录时,存储
ar
中的记录。问题在于,当两个请求在(几乎)相同的位置启动以从
aa
读取一条记录(该记录尚未在
ar
中存储其相关记录)时,
ar
记录重复

下面是一段伪代码,有助于理解这种情况:

  • 读取请求的
    aa
    记录

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

  • 查阅
    ai
    以了解给定
    aa
    记录的
    ar
    中存储的内容。(
    ai
    似乎有些不相关,但我发现它也必须参与锁定…可能是错误的。)

  • ar

以下是我想要实现的目标:

  • 读取请求的
    aa
    记录
无论是否使用事务,都要锁定
ar
,因此任何试图从
ar
读取的后续请求都将在此时等待,直到该请求完成

  • 扫描
    ar
    表,查看给定的
    aa
    记录是否已存储任何内容。(假设没有。)问题是,在两个同时请求的情况下,两个请求都发现给定
    aa
    记录的
    ar
    中没有记录,并且都继续插入相同的行两次。
    否则,如果有,该序列将中断,不会发生插入

  • 查阅
    ai
    以了解给定
    aa
    记录的
    ar
    中存储的内容。(
    ai
    似乎有些不相关,但我发现它也必须参与锁定…可能是错误的。)

  • ar

松开
ar上的锁

看起来很简单,我没有成功地避免重复。我正在测试bashshell中一个简单命令的并发请求(使用wget)

我花了一段时间在这里和这里学习InnoDB引擎的锁是如何工作的,并尝试了几种使用锁的方法,但仍然没有成功

我希望整个
ar
表被锁定(因为我希望防止多个请求对其进行插入),从而导致进一步尝试与该表交互,直到第一个锁被释放。但是文档中只提到“整个表”被锁定(第一个链接页面中的意图锁定部分),但没有进一步讨论,或者我无法想出如何实现它

有人能指出正确的方向吗

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

中看到刚刚提交的新行,感谢您的提示和看似专业的回复。当然(尽管问题已经太长了),现实生活中的情况要复杂得多,请求过程中还涉及许多其他查询。到目前为止,我遇到了
一般性错误:2014无法执行查询,而其他未缓冲的查询处于活动状态
,但不会放弃,这似乎是正确的选择。@MarcellFülöp,您也可以阅读我的答案,感谢您提供的链接答案。这并没有让我更接近于解决这个问题,特别是在我的应用程序中,当执行前3条语句(在您答案的第一个代码块中)时,无论下一条语句是什么(让它选择或插入),它都会失败,并出现此错误代码。为什么会这样?我试着将这3条语句放在我的应用程序代码的不同位置-相同的结果,下一条语句失败。再次感谢您的回答。我已经创建了一个简化版本的问题,它确实工作得很好。虽然我的问题所指的项目是其他开发人员的工作,而且非常复杂(使用原则1.2),我无法将此解决方案应用到该项目中,但我找到了一个解决方法。