2012-06-22 74 views
3

我有一个包含唯一产品ID列表的MySQL表(表A)。利用此表的应用程序使用多个线程,每个线程选择一个表行(最上面),使用API​​获取产品数据并将其更新到不同的表(表B)。一旦完成,该线程将删除表A中相应的产品ID行并选择另一个进行工作(循环直到表A中的所有行都已删除,而B表已更新)。mysql - 为选择查询锁定行?

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

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

+2

看到的交易,乐观/悲观锁等 – biziclop

回答

6

本地的MySQL锁定不提供此功能。你可以使用一列来执行你的“锁定”。

假设每个线程都有唯一的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将同样的方式工作。

+0

InnoDB支持行级锁,MyISAM不。 Myisam有*并发*插入,但这不是一回事。请参见[条目9](https://en.wikipedia.org/wiki/Comparison_of_MySQL_database_engines)。 –

+0

@SpencerRathbun,你是不是要把这条评论发布到我的文章上?它有什么关系? –

+0

你指出'UPDATE'会因为锁定InnoDB上的所有行而出现问题,这是不正确的,因为InnoDB没有锁定整个表,只是要更新的条目。 –

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) 

enter image description here

enter image description here