mysql -- 死锁
死鎖(Deadlock)
什么是死鎖
所謂死鎖:是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程。由于資源占用是互斥的,當(dāng)某個進(jìn)程提出申請資源后,使得有關(guān)進(jìn)程在無外力協(xié)助下,永遠(yuǎn)分配不到必需的資源而無法繼續(xù)運行,這就產(chǎn)生了一種特殊現(xiàn)象死鎖。
產(chǎn)生死鎖的四個必要條件:
(1) 互斥條件:一個資源每次只能被一個進(jìn)程使用。
(2) 請求與保持條件:一個進(jìn)程因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:進(jìn)程已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
死鎖的影響
當(dāng)產(chǎn)生某表死鎖的一開始,所有涉及這張表的操作都將受到阻塞。假設(shè)這張表在業(yè)務(wù)邏輯上是讀寫頻繁的,那就會使很多操作在那里排隊等待,而排隊等待會占用數(shù)據(jù)庫連接,當(dāng)該達(dá)到該數(shù)據(jù)庫連接數(shù)的最大承載數(shù)之后,就會使所有數(shù)據(jù)庫操作均無法再繼續(xù)下去,致使數(shù)據(jù)庫各項指標(biāo)異常,導(dǎo)致整個環(huán)境崩潰。在生產(chǎn)環(huán)境中出現(xiàn)這種問題,那是相當(dāng)致命的,當(dāng)發(fā)現(xiàn)數(shù)據(jù)庫指標(biāo)異常時因快速處理!
如何發(fā)現(xiàn)死鎖
1.查詢數(shù)據(jù)庫進(jìn)程
主要看State字段,如果出現(xiàn)大量 waiting for ..lock 即可判定死鎖:
SHOW FULL PROCESSLIST;注意:需要擁有root組權(quán)限(supper),否則只能看到當(dāng)前用戶的進(jìn)程,無法查詢所有
2.查看當(dāng)前的事務(wù)
SELECT?*?FROM?INFORMATION_SCHEMA.INNODB_TRX;
INNODB_TRX 表包含信息關(guān)于每個事務(wù)(排除只讀事務(wù))當(dāng)前執(zhí)行的在InnoDB,包含是否事務(wù)是等待一個鎖, 當(dāng)事務(wù)啟動后, SQL語句事務(wù)是正在執(zhí)行
INNODB_TRX Columns 相關(guān)列信息:
a) trx_id:innodb存儲引擎內(nèi)部事務(wù)唯一的事務(wù)id。
b) trx_state:當(dāng)前事務(wù)的狀態(tài)。
c) trx_started:事務(wù)開始的時間。
d) trx_requested_lock_id:等待事務(wù)的鎖id,如trx_state的狀態(tài)為LOCK WAIT,那么該值代表當(dāng)前事務(wù)之前占用鎖資源的id,如果trx_state不是LOCK WAIT的話,這個值為null。
e) trx_wait_started:事務(wù)等待開始的時間。
f) trx_weight:事務(wù)的權(quán)重,反映了一個事務(wù)修改和鎖住的行數(shù)。在innodb的存儲引擎中,當(dāng)發(fā)生死鎖需要回滾時,innodb存儲引擎會選擇該值最小的事務(wù)進(jìn)行回滾。
g) trx_mysql_thread_id:正在運行的mysql中的線程id,show full processlist顯示的記錄中的thread_id。
h) trx_query:事務(wù)運行的sql語句,在實際中發(fā)現(xiàn),有時會顯示為null值,當(dāng)為null的時候,就是t2事務(wù)中等待鎖超時直接報錯(ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction)后,trx_query就顯示為null值
比如事務(wù)t2正在運行trx_query: update test.t1 set b='t2' where a=1的sql語句,t1先執(zhí)行,所以是trx_state: RUNNING先申請的資源一直在運行,而t2后run的所以是trx_state: LOCK WAIT一直在等待t1執(zhí)行完后釋放資源。 但是并不能仔細(xì)判斷鎖的一些詳細(xì)情況,我們需要再去看當(dāng)前鎖定的事務(wù)表數(shù)據(jù)。
3.查看當(dāng)前鎖定的事務(wù)
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;INNODB_LOCKS 表包含信息關(guān)于每個鎖一個InnoDB 事務(wù)已經(jīng)請求,但是沒有獲得鎖,每個lock一個事務(wù)持有是堵塞另外一個事務(wù)
INNODB_LOCKS Columns 相關(guān)列信息:
a) lock_id:鎖的id以及被鎖住的空間id編號、頁數(shù)量、行數(shù)量
b) lock_trx_id:鎖的事務(wù)id。
c) lock_mode:鎖的模式。
d) lock_type:鎖的類型,表鎖還是行鎖
e) lock_table:要加鎖的表。
f) lock_index:鎖的索引。
g) lock_space:innodb存儲引擎表空間的id號碼
h) lock_page:被鎖住的頁的數(shù)量,如果是表鎖,則為null值。
i) lock_rec:被鎖住的行的數(shù)量,如果表鎖,則為null值。
j) lock_data:被鎖住的行的主鍵值,如果表鎖,則為null值。
如以下查詢 :
mysql> select * from INNODB_LOCKSG
1. row?**
lock_id: 3015646:797:3:2
lock_trx_id: 3015646
lock_mode: X
lock_type: RECORD
lock_table:?test.t1
lock_index: PRIMARY
lock_space: 797
lock_page: 3
lock_rec: 2
lock_data: 1
2. row?**
lock_id: 3015645:797:3:2
lock_trx_id: 3015645
lock_mode: X
lock_type: RECORD
lock_table:?test.t1
lock_index: PRIMARY
lock_space: 797
lock_page: 3
lock_rec: 2
lock_data: 1
2 rows in set (0.00 sec)
這里我們可以看到當(dāng)前的鎖信息了,2個事務(wù)都鎖定了,看相同的數(shù)據(jù)lock_space: 797、lock_page: 3、lock_rec: 2可以得出事務(wù)t1和事務(wù)t2訪問了相同的innodb數(shù)據(jù)塊,再通過lock_data字段信息lock_data: 1,看到鎖定的數(shù)據(jù)行都是主鍵為1的數(shù)據(jù)記錄,可見2個事務(wù)t1和t2都申請了相同的資源,因此會被鎖住,事務(wù)在等待。
通過lock_mode: X值也可以看出事務(wù)t1和t2申請的都是排它鎖。
PS:當(dāng)執(zhí)行范圍查詢更新的時候,這個lock_data的值并非是完全準(zhǔn)確。當(dāng)我們運行一個范圍更新時,lock_data只返回最先找到的第一行的主鍵值id;另外如果當(dāng)前資源被鎖住了,與此同時由于鎖住的頁因為InnoDB存儲引擎緩沖池的容量,而導(dǎo)致替換緩沖池頁面,再去查看INNODB_LOCKS表時,這個lock_data會顯示未NULL值,意味著InnoDB存儲引擎不會從磁盤進(jìn)行再一次查找。
4.查看當(dāng)前等鎖的事務(wù)
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;INNODB_LOCK_WAITS 表包含了blocked的事務(wù)的鎖等待的狀態(tài)。當(dāng)事務(wù)量比較少,我們可以直觀的查看,當(dāng)事務(wù)量非常大,鎖等待也時常發(fā)生的情況下,這個時候可以通過INNODB_LOCK_WAITS表來更加直觀的反映出當(dāng)前的鎖等待情況:
INNODB_LOCK_WAITSColumns 相關(guān)列信息:
a) requesting_trx_id:申請鎖資源的事務(wù)id。
b) requested_lock_id:申請的鎖的id。
c) blocking_trx_id:阻塞的事務(wù)id。
d) blocking_lock_id:阻塞的鎖的id。
如以下查詢:
mysql> select * from INNODB_LOCK_WAITSG
1. row?**
requesting_trx_id: 3015646
requested_lock_id: 3015646:797:3:2
blocking_trx_id: 3015645
blocking_lock_id: 3015645:797:3:2
1 row in set (0.00 sec)
mysql>
這里我們可以看到事務(wù)t1(3015646)申請了鎖資源,而事務(wù)t2(3015645)則阻塞了事務(wù)t1的申請。
如何處理死鎖
殺死進(jìn)程
通過以上方法一可以查詢對應(yīng)死鎖的數(shù)據(jù)庫進(jìn)程,可以直接殺掉
kill 進(jìn)程ID如果系統(tǒng)資源充足,進(jìn)程的資源請求都能夠得到滿足,死鎖出現(xiàn)的可能性就很低,否則就會因爭奪有限的資源而陷入死鎖。其次,進(jìn)程運行推進(jìn)順序與速度不同,也可能產(chǎn)生死鎖。
雖然不能完全避免死鎖,但可以使死鎖的數(shù)量減至最少。將死鎖減至最少可以增加事務(wù)的吞吐量并減少系統(tǒng)開銷,因為只有很少的事務(wù)回滾,而回滾會取消事務(wù)執(zhí)行的所有工作。由于死鎖時回滾而由應(yīng)用程序重新提交。
下列方法有助于最大限度地降低死鎖:
(1)按同一順序訪問對象。
(2)避免事務(wù)中的用戶交互。
(3)保持事務(wù)簡短并在一個批處理中。
(4)使用低隔離級別。
(5)使用綁定連接。
轉(zhuǎn)載于:https://www.cnblogs.com/daijiabao/p/11286864.html
總結(jié)
以上是生活随笔為你收集整理的mysql -- 死锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Django的简单介绍及虚拟环境的搭建、
- 下一篇: CSS中z-index属性的简单理解