Innodb
InnoDB 引擎似乎在 Mysql5.7 中自動鎖定表
我有一個名為學生的表,例如:
mysql> select * from students; +----+-------+---------+ | id | name | classId | +----+-------+---------+ | 1 | Kris | 7 | | 2 | Tom | 7 | | 3 | Mary | 2 | | 4 | Leon | 2 | | 5 | Mario | 3 | +----+-------+---------+ 5 rows in set (0.00 sec)
我執行下面的sql語句,但不給出
commit
語句:set autocommit = 1; start transaction; update students set classId = 1 where id = 1;
之後,我將打開另一個會話並執行以下 sql 語句:
set autocommit = 1; start transaction; update students set classId = 1 where id = 2;
現在,整個外殼螢幕將阻塞並且沒有響應。過了一會兒它會給我一個錯誤,類似於這個:
1205 Lock wait timeout exceeded; try restarting transaction
所以,我很困惑為什麼 InnoDB 引擎會給我一個表上的行級鎖?在這種情況下,為什麼 MySQL 會阻止我對另一行的更新?
對於剛剛從手冊中複製和粘貼而與您的問題無關的其他答案,我深表歉意。
這是一個常見的誤解——Innodb 不做全表鎖來確保事務之間的隔離——但是,它預設應用行鎖和間隙鎖來確保不會發生幻讀。因為您的表沒有索引,所以進行間隙鎖定的唯一(低效)方法是在每一行和之間的每個間隙中設置單獨的鎖定(例如,如果您嘗試插入一個 id 為 0 的新行,它也應該被阻止。
您有兩個選擇:在 id 上創建一個索引(可能主鍵是正確的方法),因此由於新索引,實際上只有一行被鎖定,或者將您的預設隔離級別更改為讀取已送出(
SET SESSION transaction_isolation='READ-COMMITTED';
)。這是 dba.stackexchange 上的一個常見問題,所以在這裡你有一個更詳細的解釋,我在另一個類似的問題上寫過:MariaDB - “ERROR 1205 … Lock wait timeout exceeded; …” when doing multiple parallel UPDATEs against different rows
但是,在您的情況下,我強烈建議您走創建索引的路線。