3

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

如何防止我的应用程序线程意外处理表 A 的同一行?有没有办法锁定一行不被选中?

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

4

2 回答 2

6

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

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

一个线程会像这样抓取一行:

UPDATE mytable
SET thread_owner = :my_threadID
WHERE thread_owner = 0
LIMIT 1

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

SELECT *
FROM mytable
WHERE thread_owner = :my_threadID

然后处理,最后删除。

此解决方案适用于 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;

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

于 2012-06-22T14:32:46.483 回答
0

尝试使用“锁定表”命令,我使用 2 个窗口向您展示:

jcho_1> lock table t1 write;
Query OK, 0 rows affected (0.00 sec)

jcho_2> select * from t1;

jcho_2 等待释放表以便能够读取,当 jcho_1 执行此操作时:

jcho_1> unlock tables;
Query OK, 0 rows affected (0.00 sec)

jcho_2 能够处理他的查询。

jcho_2> select * from t1;
+----------+-------------+--------------+---------------------+
| actor_id | first_name  | last_name    | last_update         |
+----------+-------------+--------------+---------------------+
|      206 | a           | b            | 0000-00-00 00:00:00 |
|       71 | ADAM        | GRANT        | 2006-02-15 04:34:33 |
|      132 | ADAM        | HOPPER       | 2006-02-15 04:34:33 |
...
|        0 | 0           | 0            | 0000-00-00 00:00:00 |
+----------+-------------+--------------+---------------------+
202 rows in set (1 min 27.67 sec)

在此处输入图像描述

在此处输入图像描述

于 2012-06-22T14:06:41.977 回答