日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

01. MySQL 事務(wù)死鎖現(xiàn)象及原因初步判斷

做IT的幾乎每天都接觸 MySql,但是 Mysql 事務(wù)死鎖卻并不常見(jiàn),前段時(shí)間就讓我遇到了。異常日志如下

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

從日志看是發(fā)生了 Lock wait timeout exceeded 異常。

Lock wait timeout exceeded:后提交的事務(wù)等待前面處理的事務(wù)釋放鎖,但是在等待的時(shí)候超過(guò)了mysql的鎖等待時(shí)間,就會(huì)引發(fā)這個(gè)異常。

PreparedStatementCallback; SQL [
UPDATE sf_wx_keyword_rule
SET status = ?,
last_update_time = last_update_time
WHERE id = ?];
Lock wait timeout exceeded;
try restarting transaction;

發(fā)生異常的代碼主要邏輯如下

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 


線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

分析后其實(shí)是因?yàn)橐粋€(gè)處理流程里開(kāi)了兩個(gè)事務(wù),并更新的同一條數(shù)據(jù),導(dǎo)致的事務(wù)間死鎖。

外層方法通過(guò)@Transactional 開(kāi)啟了事務(wù)1(@t1),對(duì) sf_wx_keyword_rule 一條數(shù)據(jù)做更新,內(nèi)層方法通過(guò) REQUIRES_NEW 又開(kāi)啟了一個(gè)新事務(wù)2(@t2),并對(duì)sf_wx_keyword_rule 的同一條數(shù)據(jù)做更新。

begin @t1;
UPDATE table SET status = ? WHERE id = 1
begin @t2;
UPDATE table SET status = ? WHERE id = 1
commit @t2;
commit @t1;

結(jié)論:由于 @t1 和 @t2 更新的是同一條數(shù)據(jù),所以 @t2 的執(zhí)行需要依賴(lài) @t1 的提交,而@t1 的提交又需要 @t2 執(zhí)行完。所以?xún)蓚€(gè)事務(wù)互相等待對(duì)方提交導(dǎo)致死鎖。

02. 復(fù)現(xiàn)及深層原因追蹤

2.1 復(fù)現(xiàn)

為了搞清楚事務(wù)死鎖,及死鎖期間 MySql 的數(shù)據(jù)狀態(tài),新建 test1 表重復(fù)上述操作

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 


線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

過(guò)了大概 30s @t2 返回鎖超時(shí),與異常日志一致。

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

2.2 原因追蹤

2.2.1 事務(wù)狀態(tài)

Mysql 事務(wù)操作會(huì)涉及到三張表

//當(dāng)前正在執(zhí)行的每個(gè)事務(wù)的信息
information_schema.innodb_trx
//當(dāng)前事務(wù)持有的鎖記錄
information_schema.innodb_locks
// 當(dāng)前被阻塞的事務(wù)鎖記錄
information_schema.innodb_lock_waits 

查詢(xún) innodb_trx 表

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

主要字段的含義

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

當(dāng)前有兩個(gè)未提交的事務(wù),trx_id=21245712 狀態(tài)為 LOCK WAIT,這條事務(wù)產(chǎn)生了一個(gè) id為 21245712:565:3:2 (innodb_locks 表的id) 的鎖,也就是該事務(wù)的 LOCK因?yàn)楸蛔枞鴮?dǎo)致事務(wù)超時(shí)。

trx_id = 21245684 是執(zhí)行完 SQL 還未提交的事務(wù)。

2.2.2 MySql 鎖

  • innodb_locks InnoDB 鎖記錄
線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

主要字段含義

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

鎖在 MySql 事務(wù)里是非常主要的,上面的事務(wù)就是通過(guò) Primary (主鍵) 在 Record (行) 上加的X (寫(xiě)) 鎖,先加的 X 鎖會(huì)成功,后加的 X 鎖就會(huì)被阻塞。下面詳細(xì)了解一下幾個(gè)主要的鎖。

基本鎖

InnoDB 行級(jí)鎖,分為共享鎖(S)和獨(dú)占鎖(X)

  • 共享鎖(Sharaed Locks: S鎖),或叫讀鎖
  • mysql允許拿到S鎖的事務(wù)讀一行
  • 加了S鎖記錄,允許其他事務(wù)再加S鎖,不允許其他事務(wù)再加X(jué)鎖
  • 語(yǔ)法:select ... lock in share mode;
  • 獨(dú)占鎖(Exclusive Locks:X鎖)或叫寫(xiě)鎖
  • mysql允許拿到X鎖的事務(wù)更新或刪除一行
  • 加了X鎖的記錄,不允許其他事務(wù)再加X(jué)鎖或S鎖
  • 語(yǔ)法:select … for update;

所以出現(xiàn)上述事務(wù)死鎖超時(shí)的原因是 UPDATE 會(huì)在記錄上加 X 鎖,阻塞了另一個(gè)事務(wù)對(duì)同一數(shù)據(jù)加的 X 鎖。

延伸一下,有 X 鎖之后,我們還能正常的讀數(shù)據(jù)嗎?答案是可以的。

select * from test1;

普通的 SELECT 語(yǔ)句上沒(méi)有加鎖,只有 select ... lock in share mode; 才會(huì)加 S 鎖。

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 


線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 


線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

下面是 MySql 的其他鎖

意向鎖

InnoDB為了支持多粒度(表鎖和行鎖)的鎖并存,引入意向鎖。意向鎖是表級(jí)鎖,分為IS鎖和IX鎖。

  • 意向共享鎖(IS)事務(wù)在請(qǐng)求S鎖前,需要先獲得對(duì)應(yīng)的IS鎖
  • 意向排他鎖 (IX)事務(wù)在請(qǐng)求X鎖前,需要先獲得對(duì)應(yīng)的IX鎖

鎖兼容矩陣

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

自增鎖 auto-inc lock

AUTO-INC鎖是事務(wù)中的一種特殊的表級(jí)鎖,通過(guò)AUTO_INCREMENT的列來(lái)實(shí)現(xiàn),這種鎖是作用于語(yǔ)句的而不是事務(wù)。

記錄鎖 record Lock

即行鎖。單條索引記錄上加鎖,record lock鎖住的永遠(yuǎn)是索引,而非記錄本身。

間隙鎖 gap lock

區(qū)間鎖, 僅僅鎖住一個(gè)索引區(qū)間(開(kāi)區(qū)間)。在索引記錄之間的間隙中加鎖,或者是在某一條索引記錄之前或者之后加鎖,并不包括該索引記錄本身。GAP鎖的目的是為了防止同一事務(wù)的兩次當(dāng)前讀,出現(xiàn)幻讀的情況。

臨鍵鎖 next key lock

行鎖和間隙鎖組合起來(lái)就叫Next-Key-Lock,左開(kāi)右閉區(qū)間。默認(rèn)情況下,innodb使用next-key locks來(lái)鎖定記錄。但當(dāng)查詢(xún)的索引含有唯一屬性的時(shí)候,Next-Key Lock 會(huì)進(jìn)行優(yōu)化,將其降級(jí)為Record Lock,即僅鎖住索引本身,不是范圍。

插入意向鎖 insert intention lock

Gap Lock中存在一種插入意向鎖(Insert Intention Lock),在insert操作時(shí)產(chǎn)生。在多事務(wù)同時(shí)寫(xiě)入不同數(shù)據(jù)至同一索引間隙的時(shí)候,并不需要等待其他事務(wù)完成,不會(huì)發(fā)生鎖等待。 假設(shè)有一個(gè)記錄索引包含鍵值4和7,不同的事務(wù)分別插入5和6,每個(gè)事務(wù)都會(huì)產(chǎn)生一個(gè)加在4-7之間的插入意向鎖,獲取在插入行上的排它鎖,但是不會(huì)被互相鎖住,因?yàn)閿?shù)據(jù)行并不沖突。

注:插入意向鎖并非意向鎖,而是一種特殊的間隙鎖。

如果插入前,該間隙已經(jīng)有g(shù)ap鎖,那么insert 會(huì)申請(qǐng)插入意向鎖。因?yàn)榱吮苊饣米x,當(dāng)其他事務(wù)持有該間隙的間隔鎖,插入意向鎖就會(huì)被阻塞(不用直接用gap鎖,是因?yàn)間ap鎖不互斥)。

  • innodb_lock_waits 被阻塞的鎖記錄

這張表里有記錄就說(shuō)明有事務(wù)被阻塞里。

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

主要字段含義

線上 MySql 事務(wù)死鎖,應(yīng)該怎么排查解決?

 

03. 解決方案及總結(jié)

線上遇到死鎖怎么解決?最快的方式當(dāng)然是 kill 事務(wù),重啟服務(wù),根本原因還是需要看這三張表,以后再遇到數(shù)據(jù)庫(kù)死鎖、事務(wù)死鎖,查這三張表就差不多知道原因了。

我們?cè)撊绾伪苊馑梨i呢?常規(guī)的回答都是以固定的順序訪問(wèn)數(shù)據(jù)。但本案例是因?yàn)槭褂昧?nbsp;REQUIRES_NEW 導(dǎo)致。

使用 REQUIRES_NEW 的原因以下場(chǎng)景,內(nèi)層事務(wù)是一個(gè)批量更新,但是又不希望因?yàn)槟骋粭l失敗而影響其他的更新。

begin @t1
aMApper.update()
for pojo in pojos:
  begin @t2
  bMapper.update(pojo)
  rpc.update()
  commit
commit

所以一定要避免內(nèi)外雙層事務(wù)修改同一條數(shù)據(jù)的情況,對(duì)于 Spring 事務(wù)傳播機(jī)制也要熟知其作用。

要保證數(shù)據(jù)的最終一致性,應(yīng)該寫(xiě)成一個(gè)Job,更新失敗后不斷的去補(bǔ)償。

公眾號(hào):看起來(lái)很美(kanqilaihenmei_)

分享到:
標(biāo)簽:死鎖 事務(wù) MySql
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定