查看mysql死鎖日志
show engine innodb status
找到信息中LATEST DETECTED DEADLOCK這一行,可以看到mysql的死鎖信息詳情
------------------------
LATEST DETECTED DEADLOCK
------------------------
2021-08-25 14:13:37 0x7facac6b8700
*** (1) TRANSACTION:
TRANSACTION 1589867098, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
LOCK WAIT 508 lock struct(s), heap size 57552, 4 row lock(s)
MySQL thread id 201608808, OS thread handle 140379228206848, query id 3088485657 172.18.119.16 root updating
UPDATE web_viewlog SET viewcount=viewcount+1,lasttime='2021-08-25 14:13:37' WHERE uid=2150174 and kename='21es1mmi'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 564 page no 16179 n bits 208 index PRIMARY of table `w3cschool`.`web_viewlog` trx id 1589867098 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 16; compact format; info bits 0
MySQL有三種鎖的級(jí)別:頁級(jí)、表級(jí)、行級(jí)。
表級(jí)鎖:開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
行級(jí)鎖:開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
頁面鎖:開銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。
行級(jí)鎖
行級(jí)鎖在使用的時(shí)候并不是直接鎖掉這行記錄,而是鎖索引
如果一條sql用到了主鍵索引(mysql主鍵自帶索引),mysql會(huì)鎖住主鍵索引;
如果一條sql操作了非主鍵索引,mysql會(huì)先鎖住非主鍵索引,再鎖定主鍵索引.
什么情況下會(huì)造成死鎖
所謂死鎖<DeadLock>: 是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過程中,
因爭(zhēng)奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。
此時(shí)稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等竺的進(jìn)程稱為死鎖進(jìn)程。
表級(jí)鎖不會(huì)產(chǎn)生死鎖.所以解決死鎖主要還是針對(duì)于最常用的InnoDB。
收集死鎖信息:
- 利用命令 SHOW ENGINE INNODB STATUS查看死鎖原因。
- 調(diào)試階段開啟 innodb_print_all_deadlocks,收集所有死鎖日志。
減少死鎖:
- 使用事務(wù),不使用 lock tables 。
- 保證沒有長(zhǎng)事務(wù)。
- 操作完之后立即提交事務(wù),特別是在交互式命令行中。
- 如果在用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),嘗試降低隔離級(jí)別。
- 修改多個(gè)表或者多個(gè)行的時(shí)候,將修改的順序保持一致。
- 創(chuàng)建索引,可以使創(chuàng)建的鎖更少。
- 最好不要用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE)。
- 如果上述都無法解決問題,那么嘗試使用 lock tables t1, t2, t3 鎖多張表
解決方法
首先先用sql查詢一下mysql的事務(wù)處理表
select * from information_schema.INNODB_TRX;
正常情況下的狀態(tài)都是RUNNING,但是在被鎖之后就會(huì)變成LOCK WAIT ,
一旦出現(xiàn)這種情況,就得殺死這個(gè)進(jìn)程,如果進(jìn)程殺不死就只能重啟Mysql服務(wù)了。
殺死進(jìn)程
kill 進(jìn)程ID