我有一个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行。
答案 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)