亚洲精品中文免费|亚洲日韩中文字幕制服|久久精品亚洲免费|一本之道久久免费

<optgroup id="cczp1"><ruby id="cczp1"><cite id="cczp1"></cite></ruby></optgroup>
  • <acronym id="cczp1"></acronym>
    <acronym id="cczp1"><option id="cczp1"><ol id="cczp1"></ol></option></acronym>
    <delect id="cczp1"></delect>
    <center id="cczp1"></center>
    <delect id="cczp1"></delect><em id="cczp1"><button id="cczp1"><blockquote id="cczp1"></blockquote></button></em>
    1. <optgroup id="cczp1"><td id="cczp1"><dfn id="cczp1"></dfn></td></optgroup>

      記一次排查線上MySQL死鎖過(guò)程,不能只會(huì)curd,還要知道加鎖原理

      記一次排查線上MySQL死鎖過(guò)程,不能只會(huì)curd,還要知道加鎖原理

      昨晚我正在床上睡得著著的,突然來(lái)了一條短信。

      啥,線上MySQL死鎖了,我趕緊登錄線上系統(tǒng),查看業(yè)務(wù)日志。

      能清楚看到是這條insert語(yǔ)句發(fā)生了死鎖。

      MySQL如果檢測(cè)到兩個(gè)事務(wù)發(fā)生了死鎖,會(huì)回滾其中一個(gè)事務(wù),讓另一個(gè)事務(wù)執(zhí)行成功。很明顯,我們這條insert語(yǔ)句被回滾了。

      insert into user (id, name, age) values (6, ‘張三’, 6);

      但是我們?cè)趺磁挪檫@個(gè)問(wèn)題呢?

      到底跟哪條SQL產(chǎn)生了死鎖?

      好在MySQL記錄了最近一次的死鎖日志,可以用命令行工具查看:

      show engine innodb status;

      在死鎖日志中,可以清楚地看到這兩條insert語(yǔ)句產(chǎn)生了死鎖,最終事務(wù)2被會(huì)回滾,事務(wù)1執(zhí)行成功。

      # 事務(wù)1insert into user (id,name,age) values (5,’張三’,5);# 事務(wù)2insert into user (id,name,age) values (6,’李四’,6);

      這兩條insert語(yǔ)句,怎么看也不像能產(chǎn)生死鎖,我們來(lái)還原一下事發(fā)過(guò)程。

      先看一下對(duì)應(yīng)的Java代碼:

      @Override@Transactional(rollbackFor = Exception.class)public void insertUser(User user) { User userResult = userMapper.selectByIdForUpdate(user.getId()); // 如果userId不存在,就插入數(shù)據(jù),否則更新 if (userResult == null) { userMapper.insert(user); } else { userMapper.update(user); }}

      業(yè)務(wù)邏輯代碼很簡(jiǎn)單,如果userId不存在,就插入數(shù)據(jù),否則更新user對(duì)象。

      從死鎖日志中,我們看到有兩條insert語(yǔ)句,很明顯userId=5和userId=6的數(shù)據(jù)都不存在。

      所以對(duì)應(yīng)的SQL執(zhí)行過(guò)程,可能就是這樣的:

      先用for update加上排他鎖,防止其他事務(wù)修改當(dāng)前數(shù)據(jù),然后再insert數(shù)據(jù),最后發(fā)生了死鎖,事務(wù)2被回滾。

      兩個(gè)事務(wù)分別在兩個(gè)主鍵ID上面加鎖,為什么會(huì)產(chǎn)生死鎖呢?

      如果看過(guò)上篇文章,就會(huì)明白。

      當(dāng)id=5存在這條數(shù)據(jù)時(shí),MySQL就會(huì)加Record Locks(記錄鎖),意思就是只在id=5這一條記錄上加鎖。

      當(dāng)id=5這條記錄不存在時(shí),就會(huì)鎖定一個(gè)范圍。

      假設(shè)表中的記錄是這樣的:

      id

      name

      age

      1

      王二

      1

      10

      一燈

      10

      select * from user where id=5 for update;

      這條select語(yǔ)句鎖定范圍就是 (1, 10]。

      最后兩個(gè)事務(wù)的執(zhí)行過(guò)程就變成了:

      通過(guò)這個(gè)示例看到,兩個(gè)事務(wù)都可以先后鎖定 (1, 10]這個(gè)范圍,說(shuō)明MySQL默認(rèn)加的臨鍵鎖的范圍是可以交叉的。

      那怎么解決這個(gè)死鎖問(wèn)題呢?

      我能想到的解決辦法就是,把這兩個(gè)語(yǔ)句select和insert,合并成一條語(yǔ)句:

      insert into user (id,name,age) values (5,’張三’,5) on duplicate key update name=’張三’,age=5;

      大家有什么好辦法嗎?

      這個(gè)死鎖情況,還是挺常見(jiàn)的,趕緊回去翻一下項(xiàng)目代碼有沒(méi)有這樣的問(wèn)題。

      推薦閱讀:《我愛(ài)背八股系列》

      為什么要用MQ?MQ的作用有哪些? 高并發(fā)場(chǎng)景下,如何保證數(shù)據(jù)的一致性的? 如何進(jìn)行分庫(kù)分表?分庫(kù)分表后有哪些問(wèn)題以及對(duì)應(yīng)的解決方案。 高并發(fā)下怎么生成訂單ID?以及每種方案的優(yōu)缺點(diǎn)。 如何實(shí)現(xiàn)分布式鎖?使用數(shù)據(jù)庫(kù)、分布式數(shù)據(jù)庫(kù)、分布式協(xié)調(diào)服務(wù)分別如何實(shí)現(xiàn)?

      MySQL索引底層數(shù)據(jù)結(jié)構(gòu)為什么要用B+樹(shù)?以及紅黑樹(shù)、B樹(shù)的優(yōu)缺點(diǎn)。

      一篇文章講清楚MySQL的聚簇/聯(lián)合/覆蓋索引、回表、索引下推

      ThreadLocal線上故障復(fù)盤,差點(diǎn)丟了工作。詳解MySQL事務(wù)底層原理一文講清楚MySQL的所有鎖

      MySQL update語(yǔ)句加鎖過(guò)程和原理

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
      用戶投稿
      上一篇 2022年6月13日 06:07
      下一篇 2022年6月13日 06:07

      相關(guān)推薦

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息