mysql - 为选择查询锁定行?

时间:2012-06-22 13:49:10

标签: 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行。

2 个答案:

答案 0 :(得分:6)

原生MySQL锁定不提供此功能。您可以使用列来执行"锁定#34;。

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

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

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

然后选择这样的行(如果没有要处理的行,它可能不返回任何内容):

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都将以相同的方式工作。

答案 1 :(得分:0)

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

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

jcho_2> select * from t1;
当jcho_1执行此操作时,

jcho_2等待释放表才能读取:

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)

enter image description here

enter image description here