2012-10-06 66 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對答案添加了一個編輯。 –