2012-01-13 138 views
25

根據MySql文檔,MySql支持多粒度鎖定(MGL)。MySQL'select for update'行爲

殼體-1

開業終端-1:

//連接到mysql

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

mysql> select id, status from tracking_number limit 5 for update; 
+----+--------+ 
| id | status | 
+----+--------+ 
| 1 |  0 | 
| 2 |  0 | 
| 3 |  0 | 
| 4 |  0 | 
| 5 |  0 | 
+----+--------+ 
5 rows in set (0.00 sec) 
mysql> 

離開它打開和打開終端-2:

//連接到MySQL

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

mysql> select id, status from tracking_number limit 5 for update; 

<!-- Hangs here. and after some time it says--> 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

雖然有很多行可供檢索,但T2會一直等到t1完成。

情形2

左終端-1作爲在is.Now終端-2:

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

<!-- case 2.1 --> 
mysql> select id, status from tracking_number where id=1; 
+----+--------+ 
| id | status | 
+----+--------+ 
| 1 |  0 | 
+----+--------+ 
1 row in set (0.00 sec) 

mysql> select id, status from tracking_number where id=2; 
+----+--------+ 
| id | status | 
+----+--------+ 
| 2 |  0 | 
+----+--------+ 
1 row in set (0.00 sec) 

<!-- case 2.2 --> 
mysql> select * from tracking_number where id=2 for update; 
<!-- Hangs here. and after some time --> 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 
  1. 但爲什麼在情況1,T2等待相同的行集T1已鎖定?

  2. 這是否意味着無界選擇查詢(即使有limint參數,我也嘗試過不同的範圍)也會阻止整個表?

  3. 有什麼辦法讓事務獨立鎖定而不指定記錄的字段(即,不使用其中字段=值)?
  4. 通常(或按照Java併發鎖定),寫鎖定是獨佔的,讀取不是。在2.1情況下,雖然記錄處於寫鎖定模式,但T2如何讀取相同的記錄?由於這是允許的,鎖定它有什麼意義?
  5. 可以理解情況2.2。

打開一個終端和一個交易:

mysql> update tracking_number set status=4 where status=0 limit 5; 
Query OK, 5 rows affected (0.00 sec) 
Rows matched: 5 Changed: 5 Warnings: 0 

離開那裏,打開另一個終端和交易:

mysql> update tracking_number set status=5 where status=0 limit 5; 

T2沒有成功,直到我提交(或回滾)T1。

  1. 這是爲什麼?

回答

22

讓我經過你的情況,並解釋這些鎖是如何工作的:

1例

T1希望在您的測試表更新一些行。此事務對前5行中的所有表和X鎖執行IX鎖定。

T2想要更新測試表中的某些行。這個事務將IX(因IX與IX兼容)鎖定在所有的表上,並嘗試前5行,但它不能這樣做,因爲X與X不兼容

所以我們很好。

2.1的情況下

T1希望在您的測試表更新一些行。該事務對前5行上的所有表和X鎖進行IX鎖定。

T2想要從您的測試表中選擇一些行。而且它不會把任何鎖(因爲InnoDB提供非鎖定讀取)

2.1的情況下

T1希望在您的測試表更新一些行。該事務對前5行上的所有表和X鎖進行IX鎖定。

T2想要更新(選擇更新)測試表中的某些行。將IS放在整個表上,並嘗試在該行上獲得S鎖定並因爲X和S不兼容而失敗。


而且始終注意隔離級別:不同層次原因不同的機制來釋放/獲取鎖

希望它可以幫助

+0

感謝@ravnur。有沒有辦法讓事務獨立鎖定而不指定記錄的字段(即,不使用where field = value)? – 2012-07-28 19:09:20

+1

獨立=同時?如果「是」,除了將隔離級別設置爲「髒讀」之外無法執行此操作(最好不要嘗試此選項)。如果你的答案是「否」,你可以嘗試'LOCK TABLE'或者設置隔離級別爲「SERIALIZABLE」(但我想你的答案應該是「是」)。 – ravnur 2012-07-29 21:09:09

+0

我的回答是「是」。謝謝你的澄清。 – 2012-08-07 08:25:06