2012-10-06 30 views
9

我希望并发事务从表中选择一行,将其标记为“脏”,以便其他事务不能选择它,然后执行其余的交易。使用select ...进行更新以隔离行的最小示例

我在使用select... for update时遇到了麻烦,因为第二笔交易争执相同。请提供不同事务的最小示例,以选择不同的行

我的数据是:

mysql> select * from SolrCoresPreallocated; 
+----+-------------+-----+-----+ 
| id | used_status | sid | cid | 
+----+-------------+-----+-----+ 
| 1 |   0 | 0 | 400 | 
| 2 |   0 | 0 | 401 | 
| 3 |   0 | 0 | 402 | 
| 4 |   0 | 0 | 403 | 
| 5 |   0 | 0 | 404 | 
| 6 |   0 | 0 | 405 | 
+----+-------------+-----+-----+ 
6 rows in set (0.00 sec) 

和预期这东西是不工作:

mysql> begin; 
Query OK, 0 rows affected (0.00 sec) 

mysql> select * from SolrCoresPreallocated order by id limit 1 for update; 
+----+-------------+-----+-----+ 
| id | used_status | sid | cid | 
+----+-------------+-----+-----+ 
| 1 |   0 | 0 | 400 | 
+----+-------------+-----+-----+ 
1 row in set (0.00 sec) 

...set the used_status to 1 
...perform the rest of the operations 

...作为第二个交易起

mysql> begin; 
Query OK, 0 rows affected (0.00 sec) 

mysql> select * from SolrCoresPreallocated order by id limit 1 for update; 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 
mysql> rollback; 
Query OK, 0 rows affected (0.00 sec) 
+0

它做了什么,你没有想到? –

+0

也包括那 – aitchnyu

回答

7

SELECT ... FOR UPDATE锁定的行(独占)模式,这意味着第二个选择不能继续,直到第一个完成特德或回滚。这是因为第二个选择的结果可能会受到您所锁定行的内容的影响,所以需要对该行读取锁以检查。

如果您创建了UNIQUE INDEX,例如id,您可以这样做;

select * from SolrCoresPreallocated where id=1 for update; 

在第一笔交易中;

select * from SolrCoresPreallocated where id=2 for update; 
在独立的第二个

,因为唯一索引可以让第二选择找到正确的行,而不读锁定的第一个。

编辑:要尽快得到一个“免费”的行,唯一的办法就是做两个交易;

  • BEGIN/SELECT FOR UPDATE/UPDATE to busy/COMMIT to get the row。
  • BEGIN/< process row>/UPDATE释放/ COMMIT来处理该行并释放它。

这意味着您可能需要补偿操作以防万一进程失败并回滚会更新该行的事务,但由于MySQL(或针对该事件的标准SQL)没有概念“获得下一个解锁的行”,你没有太多的选择。

+0

但我需要选择**下一个**免费行;我不能像这样查询,即使它可以工作 – aitchnyu

+0

@aitchnyu对答案添加了一个编辑。 –