天天看點

MySQL InnoDB Lock Modes行鎖的S鎖和X鎖意向鎖(Intention lock)死鎖

行鎖的S鎖和X鎖

Innodb實施标準的行級鎖,其中有兩種類型的鎖:

Shared lock即共享鎖,S鎖。如果事務對資料行r持有S鎖,那麼允許其它事務對資料行r持有S鎖,但不允許其它事務對資料行持有X鎖。

Exclusive lock即排它鎖,X鎖。如果事務T1對資料行r持有X鎖,那麼就不允許其它事務對資料行持有S鎖或X鎖,除非等到T1釋放r上的X鎖

意向鎖(Intention lock)

Innodb支援多粒度鎖,即允許記錄鎖(record locks)和表鎖共存(InnoDB supports multiple granularity locking which permits coexistence of record locks and locks on entire tables)。為了在多個粒度級别上實作鎖定,innodb引進了意向鎖。有兩種意向鎖:

Intention shared(IS):意向共享鎖,表示事務T将要對表中資料行加S鎖,而先在表級别上加的就是IS鎖;

Intention exclusive(IX):意向排它鎖,表示事務T将要對表中資料行加X鎖,而先在表級别上加的就是IX鎖;

意圖鎖是表鎖,它訓示事務稍後将在表資料行上加何種類型的鎖。IS鎖表示事務稍後會在資料行上加S鎖,IX鎖表示事務稍後會在資料行上加X鎖。常見的,像“select … lock in share mode”語句會加IS鎖,“select … for update”語句會加IX鎖。

是以,引入意圖鎖的目的就是為了支援多粒度鎖定,并能通過意圖鎖顯示事務鎖定了表中的某些行,或者将要鎖定表中的某些行。

意圖鎖的協定如下:

一個事務要想獲得行上的S鎖,必須先擷取該表上的IS或者更強的鎖;

一個事務要想獲得行上的X鎖,必須先擷取該表上的IX鎖。

四種鎖之間的相容性如下:

MySQL InnoDB Lock Modes行鎖的S鎖和X鎖意向鎖(Intention lock)死鎖

如果事務請求的鎖與現有鎖相容,則授予該事務鎖;但如果與現有鎖沖突,則不授予該事務鎖,事務需要等待現有鎖被釋放後才能擷取鎖。

說明:

個人認為,上面的S和X鎖是表級别的S和X鎖。但之前和朋友讨論,說沒有表級别的S和X鎖,隻有行級别的S和X鎖,并上面指的是行級别的S和X鎖。後來發現在姜承堯的innodb内幕這本書中,也提到上面指的是行級别的S和X鎖。

是以有些疑惑的就是:鎖的粒度不同,如何讨論相容性?更何況意圖鎖引入的目的就是為了支援mysql的多粒度鎖定。

死鎖

死鎖示範:

會話1上開啟事務T1:

mysql> start transaction;
mysql> select * from ecs_payment where pay_id=2332 lock in share mode;
+--------+----------+----------+---------+----------+-----------+------------+---------+--------+-----------+
| pay_id | pay_code | pay_name | pay_fee | pay_desc | pay_order | pay_config | enabled | is_cod | is_online |
+--------+----------+----------+---------+----------+-----------+------------+---------+--------+-----------+
|   2332 | 83       | ^{}      | 4090.99 | bwlw]^k  |        13 | lb^wkw]    |       1 |      0 |         0 |
+--------+----------+----------+---------+----------+-----------+------------+---------+--------+-----------+           

會話2上開啟事務T2:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update ecs_payment set pay_name='tiatiao' where pay_id=2332;    --被卡住           

會話1的事務T1再執行操作:

mysql> delete from ecs_payment where pay_id=2332;
Query OK, 1 row affected (0.00 sec)           

這時再看會話2的事務T2,會輸出如下資訊:

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction           

發生死鎖的四個必要條件:

互斥條件

不可剝奪

請求與保持

循環等待

注意:

如果InnoDB螢幕輸出的最新檢測到的死鎖部分包含如下輸出資訊:

TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH, WE WILL ROLL BACK FOLLOWING TRANSACTION           

這表明鎖等待清單上的事務數量已經達到了200個的限制,超過200個事務的等待清單被視為死鎖,這個數量限制和參數LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK有關

繼續閱讀