在事務(wù)中執(zhí)行select…for update,update,delete會引起鎖叉袍,對于事務(wù)的修改涮毫,事務(wù)中會使用X鎖葡幸,X鎖是行級鎖,InnDB行鎖是通過給索引上的索引項加鎖實現(xiàn)的(只有通過索引條件檢索數(shù)據(jù)(即explain sql語句水慨,type=index或range),InnoDB才使用行級鎖敬扛,否則使用表鎖)
為了驗證這個晰洒,我做了一個小測驗
數(shù)據(jù)表t_bitfly:
CREATE TABLE `t_bitfly` (
`id` bigint(20) NOT NULL DEFAULT '0',
`value` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
session1:
start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_bitfly where id < 4 for update;
+----+-------+
| id | value |
+----+-------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+-------+
3 rows in set (0.00 sec)
session2:
start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_bitfly where id >= 4 for update;
select * from t_bitfly where id >= 4 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
出現(xiàn)死鎖
想不明白啊,不是應(yīng)該只鎖住<4的那幾行嗎
explain:
mysql> explain select * from t_bitfly where id < 4\G;
*************************** 1\. row ***************************
id: 1
select_type: SIMPLE
table: t_bitfly
partitions: NULL
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: NULL
rows: 3
filtered: 100.00
Extra: Using where; Using index
type=range啥箭,使用上索引了啊谍珊,為什么,為什么急侥,不明白啊
這個問題困擾自己好久砌滞,終于在今天晚上找到答案了,恍然大悟的感覺真的是賊爽
原因:在UPDATE坏怪、DELETE操作時贝润,MySQL不僅鎖定WHERE條件掃描過的所有索引記錄,而且會鎖定相鄰的鍵值陕悬,即所謂的next-key locking题暖。
繼續(xù)做測驗
session2:
start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_bitfly where id > 5 for update;
mysql> select * from t_bitfly where id > 4 for update;
+----+-------+
| id | value |
+----+-------+
| 5 | e |
| 6 | f |
| 7 | g |
| 8 | h |
| 9 | i |
| 10 | j |
| 11 | k |
+----+-------+
7 rows in set (0.00 sec)
現(xiàn)在就不出現(xiàn)死鎖的情況下,因為此時沒有包括4
出現(xiàn)next-key有兩種情況捉超,一是上面的使用索引范圍胧卤,二是使用相等條件請求給一個不存在的記錄:
例如:
session 1:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_bitfly where id = 17 for update;
Empty set (0.00 sec)
session 2:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_bitfly values(17,'n');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
一般情況下相等情況不會出現(xiàn)鎖爭用問題
使用next-key的目的:
1)解決幻讀
2)滿足mysql的復(fù)制和恢復(fù)
帶來的問題
造成嚴(yán)重的鎖等待
如何解決:
盡量避免使用范圍條件,使用相等條件來訪問和更新數(shù)據(jù)
行鎖的使用還需要注意的幾點拼岳,否則很有可能會在執(zhí)行的時候出現(xiàn)死鎖或獲取不到鎖的情況(比如我遇到的):
1)在MySQL中枝誊,行級鎖并不是直接鎖記錄,而是鎖索引惜纸。
2)索引分為主鍵索引和非主鍵索引兩種叶撒,如果一條sql語句操作了主鍵索引绝骚,MySQL就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引(自定義索引+主鍵)祠够,MySQL會先鎖定該非主鍵索引压汪,再鎖定相關(guān)的主鍵索引
3)當(dāng)兩個事務(wù)同時執(zhí)行,一個鎖住了主鍵索引古瓤,在等待其他相關(guān)索引止剖。另一個鎖定了非主鍵索引,在等待主鍵索引落君。這樣就會發(fā)生死鎖