1. 程式人生 > >Mysql的等待鎖和死鎖

Mysql的等待鎖和死鎖

問題:

       下午因為釘釘服務異常的問題,開發的微應用一直報jsapi鑑權失敗,同時檢視日誌的時候還發現有鎖等待的錯誤日誌。報的錯誤資訊為:java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction,這是事物超時報的錯,跟蹤排查了下,發現原來從待處理訊息表中處理訊息傳送給釘釘介面時,釘釘介面訪問超時,在超時失敗前,事物會一直等待,這就造成其他執行緒再往訊息表插資料時失敗,從而報了上面的錯誤。

        Mysql查詢事務列表、鎖等待相關的sql如下:

show full processlist;
select * from information_schema.INNODB_TRX;  #當前執行的所有事物
select * from information_schema.INNODB_LOCKS;  #當前出現的鎖
select * from information_schema.INNODB_LOCK_WAITS; #鎖等待的對應關係
#事物超時的時間,預設50s,即放棄行級鎖的超時時間
show VARIABLES like 'innodb_lock_wait_timeout';
#下面兩行,如果設定為ON,則innoDB會自動檢測死鎖進行回滾,或者終止死鎖的情況。
show VARIABLES like 'innodb_table_locks'; 
show VARIABLES like 'autocommit';

       關於事物超時的相關知識,mysql資料庫自身有一個預設配置引數innodb_lock_wait_timeout來設定InnoDb放棄行級鎖的時間,預設是50s。而通過Spring的@Transaction來配置的超時時間發現實際超時時間往往會更差一點,具體移步這裡檢視

MySql鎖

關於Mysql鎖的情況,假設存在以下表:

使用者表(user)
欄位 說明 備註
id 使用者id 主鍵,不能為空
name 使用者姓名 姓名資訊

 

 

 

 

1.共享鎖

select * from user where id='1' lock in share mode;

共享鎖又稱為讀鎖,簡稱S鎖,表示多個事物對於同一資料可以共享一把鎖,都能訪問到該資料,但是隻能讀不能修改。不加共享鎖的話,資料會被其他事物修改。這是區別

2.排它鎖

update user set name='zhangsan' where id='1';

select * from user for update;

排它鎖又稱為寫鎖,簡稱X鎖,表示只能自己進行增刪改查,其他的事物只能等待。

3.表級鎖

update user set name='zhangsan' where name='wangwu';

把非主鍵作為條件的排它鎖就是表級鎖,會把整個表都鎖到,其實也算是悲觀鎖。

4.行級鎖

update user set name='zhangsan' where id='1';

把主鍵作為條件的排它鎖是行級鎖,這個我個人認為也算是樂觀鎖,通過這種方式進行更新,不影響表其他資料的讀寫。

5.所等待超時

Lock wait timeout exceeded; try restarting transaction

T1:  mysql>begin update user set name ='zhangsan' where id='5'

T2:mysql>begin update user set name='lisi' where id='5'

事物T1佔著行級鎖,不commit,那麼T2就要一直等,直到T1commit了,或者超過50s超時了。如果超時了,就報上面的錯誤。

6.死鎖

Deadlock found when trying to get lock;

T1:

mysql>begin;

mysql>update user set name='zhangsan' where id='5';

mysql>update user set name='lisi' where name='zh';

T2:

mysql>begin;

mysql>update user set name='ww' where id='5'

假如T1和T2同時執行,首先T1會佔有行級鎖,然後T2會排隊等待T1釋放行級鎖,而事物T1的第二條表鎖更新語句會等待事物2釋放行級鎖,這就出現T1等T2,T2等T1的情況,然後就死鎖了。

T1一直沒commit,那麼T2就會一直等T1,但是T1第二條語句想執行,就要等T2commit,這是死鎖出現的情況。

Mysql資料庫的內部機制會自動重啟事物T2,解決死鎖問題,保證T1正常進行,但是oracle會死鎖等待。

參考:https://blog.csdn.net/baidu_34217927/article/details/78601665

 

另:

   在釘釘開發中,非常容易出現異常的操作,釘釘的微應用允許同一個使用者同時PC線上和手機線上。我們的業務中有這樣的場景,使用者要處理問單,他同時在PC上和手機上都開啟問單,在手機上對問單進行回覆操作,此時問單狀態已發生變化了,問單已終結了。但是他立馬又在PC上對問單進行錯單轉移的操作。但其實問單已經是處理成功了,再進行其他的操作都是錯誤的。為了避免出現這種情況,在進行處理事務中,對於更新問單狀態的sql使用樂觀鎖,通過加問單id和問單狀態為條件進行update,從而避免出現這種異常情況。