mysql - 为选择查询锁定行?

Zis*_*han 3 mysql

我有一个mysql表(表-A),其中包含唯一的产品ID列表.利用此表的应用程序使用多个线程,每个线程选择一个表行(最顶层),使用API​​来获取产品数据并将其更新到另一个表(表-B).完成后,线程将删除表A中相应的产品ID行,并选择另一个要处理的行(循环直到表-A中的所有行都被删除而表-B已更新).

如何防止我的应用程序的线程意外地在表A中的同一行上工作?有没有办法锁定被选中的行?

示例:应用程序的thread-1从表A中选择row-1.从API获取并将所有相关数据更新到表B中大约需要10到15秒.当发生这种情况时,thread-2将启动并检查表-A以选择要处理的行.在这种情况下,我只想锁定第1行,这样它就不会线程2看不到/读取它而是选择第2行.

Mar*_*ams 6

本机MySQL锁定不提供此功能.您可以使用列来执行"锁定".

假设每个线程都有唯一的ID,您可以创建一个名为的列thread_owner,默认值为0.

一个线程会抓住这样一行:

UPDATE mytable
SET thread_owner = :my_threadID
WHERE thread_owner = 0
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

然后选择这样的行(如果没有要处理的行,它可能会返回none):

SELECT *
FROM mytable
WHERE thread_owner = :my_threadID
Run Code Online (Sandbox Code Playgroud)

然后处理它,最后删除它.

该解决方案适用于MyISAM和InnoDB.

但是,对于InnoDB,它可能很慢,因为每个UPDATE语句都试图锁定thread_owner = 0的所有行,除非您确定每次都以相同的顺序锁定所有行,否则它甚至可能导致死锁.因此,您可以尝试在UPDATE语句中显式锁定整个表:

LOCK TABLES mytable WRITE;
UPDATE mytable
SET thread_owner = :my_threadID
WHERE thread_owner = 0
LIMIT 1;
UNLOCK TABLES;
Run Code Online (Sandbox Code Playgroud)

这样,MyISAM和InnoDB都将以相同的方式工作.