更新時(shí)間:2022-11-18 來(lái)源:黑馬程序員 瀏覽量:
一、什么是死鎖
加鎖(Locking)是數(shù)據(jù)庫(kù)在并發(fā)訪問(wèn)時(shí)保證數(shù)據(jù)一致性和完整性的主要機(jī)制。任何事務(wù)都需要獲得相應(yīng)對(duì)象上的鎖才能訪問(wèn)數(shù)據(jù),讀取數(shù)據(jù)的事務(wù)通常只需要獲得讀鎖(共享鎖),修改數(shù)據(jù)的事務(wù)需要獲得寫(xiě)鎖(排他鎖)。當(dāng)兩個(gè)事務(wù)互相之間需要等待對(duì)方釋放獲得的資源時(shí),如果系統(tǒng)不進(jìn)行干預(yù)則會(huì)一直等待下去,也就是進(jìn)入了死鎖(deadlock)狀態(tài)。
二、死鎖產(chǎn)生的場(chǎng)景
1.數(shù)據(jù)庫(kù)表準(zhǔn)備
1.1. 創(chuàng)建數(shù)據(jù)庫(kù)表
#創(chuàng)建數(shù)據(jù)庫(kù) create database chuanzhi; #選擇數(shù)據(jù)庫(kù) use chuanzhi; #創(chuàng)建測(cè)試表 CREATE TABLE `tb_heima` ( `id` INT NOT NULL, `username` VARCHAR(45) NULL, PRIMARY KEY (`id`) ); #插入測(cè)試數(shù)據(jù) INSERT INTO `tb_heima` (`id`, `username`) VALUES ('1', '傳智教育-教育行業(yè)A股IPO第一股');
2.死鎖場(chǎng)景演示
2.1. 打開(kāi)一個(gè)dos窗口
- mysql -u賬號(hào) -p密碼,進(jìn)入mysql命令行輸入:
- 開(kāi)啟一個(gè)事務(wù),mysql> begin;
- 執(zhí)行更新語(yǔ)句,mysql> update tb_heima set username = 'heima' where id =1;
注意:此時(shí)更新是成功的,但并未提交事務(wù)。
2.2.再打開(kāi)一個(gè)dos窗口
- 登錄mysql,開(kāi)啟另一個(gè)事務(wù)操作同上。
- 再次執(zhí)行更新語(yǔ)句,mysql> update tb_heima set username = 'heima' where id =1;
注意:此時(shí)第二個(gè)窗口處于等待中,需要等待第一個(gè)窗口釋放寫(xiě)鎖才能執(zhí)行成功。
- 等待一段時(shí)候后,第二個(gè)窗口報(bào)錯(cuò)了
注意:由于第一個(gè)窗口未提交事務(wù),導(dǎo)致第二個(gè)窗口在等待一段時(shí)候后,超過(guò)鎖定等待超時(shí)。
三、解決死鎖問(wèn)題
通過(guò)mysql客戶(hù)端工具連接,按照以下步驟執(zhí)行。
- select from information_schema.innodb_lock_waits; 鎖等待的信息,可以看到堵塞和被堵塞者
注意:超過(guò)鎖定等待超時(shí)后,此條記錄會(huì)消失,也就是說(shuō)正在阻塞的記錄在此表才能查看到。
- select * from information_schema.innodb_trx; 查詢(xún)鎖事務(wù)狀態(tài)信息
注意:查詢(xún)出死鎖后,得到trx_mysql_thread_id死鎖的id。
- kill sessionId; 殺掉有問(wèn)題的session
kill 15; kill 16;
- 再次執(zhí)行select * from information_schema.innodb_trx; # 查詢(xún)鎖事務(wù)狀態(tài)信息
注意:確認(rèn)此表是否存在鎖事務(wù)記錄,如果沒(méi)有則說(shuō)明死鎖問(wèn)題已經(jīng)解決。
四、如何避免死鎖
1.對(duì)于數(shù)據(jù)庫(kù)的多表操作時(shí),盡量按照相同的順序進(jìn)行處理,盡量避免同時(shí)鎖定兩個(gè)資源,如操作A和B兩張表時(shí),總是按先A后B的順序處理, 必須同時(shí)鎖定兩個(gè)資源時(shí),要保證在任何時(shí)刻都應(yīng)該按照相同的順序來(lái)鎖定資源。
2. 所有的update和delete操作必須走唯一索引
3. SQL語(yǔ)句中不要使用太復(fù)雜的關(guān)聯(lián)多表的查詢(xún);使用“執(zhí)行計(jì)劃”對(duì)SQL語(yǔ)句進(jìn)行分析,對(duì)于有全表掃描的SQL語(yǔ)句,建立相應(yīng)的索引進(jìn)行優(yōu)化。
4. 把SELECT放在Update語(yǔ)句前
5. 避免事務(wù)中的用戶(hù)等待交互