MySQL 不得不解決的死鎖問題

2021-08-15 05:48:27 字數 3569 閱讀 1699

1.delete刪除不存在的資料導致死鎖

mysql的鎖分為三種(按照鎖定的行數劃分):

1.record lock:記錄鎖,也就是僅僅鎖著單獨的一行

2.gap lock:區間鎖,僅僅鎖住乙個區間(注意這裡的區間都是開區間,也就 是不包括邊界值,至於為什麼這麼定義?innodb官方定義的)

3.next-key lock:record lock+gap lock,所以next-key lock也就半開半閉區間,且是下界開,上界閉。(為什麼這麼定義?innodb官方定義的)

由於此處是在明確指定了no=xx的情況下丟擲了死鎖異常, 並且no建立的是普通索引, 所以此處mysql使用的應該是next-key lock(檢視何種情況下使用何種鎖

下面來舉個手冊上的例子看看next-key lock是如何上鎖的。假如乙個索引的行有10,11,13,20

那麼可能的next-key lock的包括:

(無窮小, 10]

(10,11]

(11,13]

(13,20]

(20, 無窮大)

因此對於delete刪除不存在的資料造成了區間鎖。

解決方法:

①先檢查記錄是否存在,否則不刪除

②對於同一條記錄,建議使用update

③如果鎖是gap鎖,這種死鎖需要將事務的隔離級別設定為read commit。

④對於等待鎖的的會話使用innodb_lock_wait_timeout,防止過載。

①沒有索引欄位的情況下不存在行鎖,如果加鎖,那麼排他鎖和共享鎖都會公升級為表鎖

②修改表結構時的鎖為表鎖

③修改大量資料的時候可以鎖表

④mysql的innodb儲存引擎實務鎖雖然是鎖行,但它內部是鎖索引的,根據where條件和select的值是否只有主鍵或非主鍵索引來判斷怎麼鎖,比如只有主鍵,則鎖主鍵索引,如果只有非主鍵,則鎖非主鍵索引,如果主鍵非主鍵都有,則內部會按照順序鎖

由於innodb預設是row-level lock,所以只有「明確」的指定主鍵,mysql才會執行row lock (只鎖住被選取的資料例) ,否則mysql將會執行table lock (將整個資料表單給鎖住)。

舉個例子:

假設有個表單products ,裡面有id跟name二個字段,id是主鍵。

例1: (明確指定主鍵,並且有此筆資料,row lock)

select * from products where id='3' for update;

select * from products where id='3' and type=1 for update;

例2: (明確指定主鍵,若查無此筆資料,無lock)

select * from products where id='-1' for update;

例2: (無主鍵,table lock)

select * from products where name='mouse' for update;

例3: (主鍵不明確,table lock)

select * from products where id<>'3' for update;

例4: (主鍵不明確,table lock)

select * from products where id like '3' for update;

例5:(主鍵不存在,gap鎖)

select * from products where id='50' for update; //假設50不存在

注1: for update僅適用於innodb,且必須在交易區塊(begin/commit)中才能生效。

注2: 要測試鎖定的狀況,可以利用mysql的command mode ,開二個視窗來做測試。

原文:mysql事物鎖等待超時

innodb_lock_wait_timeout

問題出現環境: 

1、在同一事務內先後對同一條資料進行插入和更新操作; 

2、多台伺服器操作同一資料庫; 

3、瞬時出現高併發現象;

1、通過下面語句查詢到為提交事務的資料,kill掉此執行緒即可。

select * from information_schema.innodb_trx
2、增加鎖等待時間,即增大下面配置項引數值,單位為秒(s)

innodb_lock_wait_timeout=500
3、優化儲存過程,事務避免過長時間的等待。

①此引擎不支援事務、也不支援行鎖。

①表鎖有兩種模式:表共享讀鎖(table read lock)和表獨佔寫鎖(table write lock)

《 mysql併發時經典常見的死鎖原因及解決方法》

原因:uk衝突導致出現gap死鎖

解決方式:

方式一:不使用自增主鍵和索引,可以使用guid(uuid中獎重複的概率是中獎概率的32次方)。

方式二:降低事務的隔離級別

方式三:使用業務鎖,使得併發序列執行。

方式四:在方式一的基礎上,將生成的guid放入到redis佇列中,提前儲備一定數量,不足時再自動生成補充(推薦)。

方式五:snowflake演算法(twtter發明的)

對於有些記錄要求存在就更新、不存在就插入,可以使用如下方式

c on duplicate key update count=count+1;
也可以使用replace

insert into player_count(player_id,count) value(1,1)
解除正在死鎖的狀態有兩種方法:

第一種:

1.查詢是否鎖表

show open tables where in_use > 0;

2.查詢程序(如果您有super許可權,您可以看到所有執行緒。否則,您只能看到您自己的執行緒)

show processlist

3.殺死程序id(就是上面命令的id列)

kill id

第二種:

1.檢視下在鎖的事務 

select * from information_schema.innodb_trx;

2.殺死程序id(就是上面命令的trx_mysql_thread_id列)

kill 執行緒id

其它關於檢視死鎖的命令:

1:檢視當前的事務

select * from information_schema.innodb_trx;
2:檢視當前鎖定的事務

select * from information_schema.innodb_locks;
3:檢視當前等鎖的事務

select * from information_schema.innodb_lock_waits;

mysql編碼不得不知的問題

1 檢視mysql相關編碼 檢視mysql資料庫所支援的編碼 showcharacterset 檢視當前變數中的一些編碼情況 show variableslike character 檢視某個資料庫的編碼 showcreatedatabasedb name 檢視某個表的字符集 showcreatet...

this指向 不得不看的this指向問題

分析this的指向共有四種型別 1 函式被呼叫時 即執行時 才會確定該函式內this的指向。因為在函式中this與arguments是兩個特殊的變數,在函式被呼叫時才會取得它們,而且搜尋這兩個變數時只會在活動物件範圍裡面去搜。2 要確定函式中this的指向,必須先找到該函式被呼叫的位置。認準第一種 ...

不得不說的「跳槽」

現實中不難發現 越是高階人才,適合的機會就越少 的現象。身處金字塔中上層的人員,無論是職位還是薪水,起點都很高,這客觀上造成適合的職位機會少,職業路徑轉換成本過高等問題。我個人認為,it技術高層人士,如果要跳槽,務必要注意三宜和三忌。忌 病急亂投醫 宜 方法得當 公升遷至較高職位的人,大多都多年不找...