成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇學(xué)會MySQL死鎖-更新插入導(dǎo)致死鎖

數(shù)據(jù)庫 MySQL
根據(jù)日志找到業(yè)務(wù)代碼,發(fā)現(xiàn)業(yè)務(wù)代碼邏輯是:先把回收單id 對應(yīng) 歷史的回收單都更新為失效,然后再插入回收單id對應(yīng)的新的回收單數(shù)據(jù)。

1 問題背景

前段時間,領(lǐng)導(dǎo)說我們業(yè)務(wù)量大漲,部門新增HC,讓我們趕緊招人。

領(lǐng)導(dǎo):經(jīng)過大家的共同努力和不懈奮斗,我們的業(yè)務(wù)量實現(xiàn)了顯著的大漲,這是對我們團隊能力和工作成果的最好證明。為了更好地應(yīng)對業(yè)務(wù)量的增長,滿足客戶的需求,我們決定在部門內(nèi)新增HC,大家行動起來吧。

。。。

面試官:你好,今天想和你聊聊MySQL數(shù)據(jù)庫中的死鎖問題。首先,你能解釋一下什么是死鎖嗎?

應(yīng)聘者:死鎖是指兩個或多個事務(wù)在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,這些事務(wù)都將無法向前推進。在MySQL中,這通常發(fā)生在多個事務(wù)嘗試以不同順序訪問相同的資源(如表或行)時。

面試官:很好,那么MySQL中死鎖發(fā)生的常見原因有哪些?

應(yīng)聘者:MySQL中死鎖的常見原因包括:

不同事務(wù)交叉鎖定資源:當兩個或多個事務(wù)相互等待對方釋放鎖定的資源時,就可能發(fā)生死鎖。索引使用不當:不恰當?shù)乃饕褂每赡軐?dǎo)致查詢鎖定更多行,增加死鎖的風(fēng)險。大量數(shù)據(jù)的修改:在處理大量數(shù)據(jù)時,尤其是同時修改多個表或行時,更容易發(fā)生死鎖。鎖升級:在某些情況下,低級鎖(如行鎖)可能會升級為更高級別的鎖(如表鎖),這也會增加死鎖的可能性。

面試官:如何分析一個SQL都加了哪些鎖呢?你需要哪些前置信息呢?

應(yīng)聘者:好的,我先說一下我的理解。

加鎖規(guī)則:兩個原則、兩個優(yōu)化、一個 bug

原則 1:加鎖的基本單位是 next-key lock,前開后閉區(qū)間

原則 2:查找過程中訪問到的對象才會加鎖

優(yōu)化 1:索引上的等值查詢,給唯一索引加鎖的時候,匹配上數(shù)據(jù),next-key lock 退化為行鎖

優(yōu)化 2:索引上的等值查詢,向右遍歷時且最后一個值不滿足等值條件的時候,next-key lock 退化為間隙鎖

一個 bug:唯一索引上的范圍查詢會訪問到不滿足條件的第一個值為止

面試官:那我有個案例,你分析分析都加了哪些鎖?是否會產(chǎn)生死鎖。我有一個回收單表,回收單id+回收類型 是唯一索引, 我先根據(jù)回收單id A更新回收單A狀態(tài),(如果數(shù)據(jù)不存在)再插入回收單A數(shù)據(jù)。我再根據(jù)回收單id B更新回收單B狀態(tài),(如果數(shù)據(jù)不存在)再插入回收單B數(shù)據(jù)。

應(yīng)聘者:。。。

上面是國內(nèi)開發(fā)者在找工作過程中常被問到的問題,大家吐槽是八股文,過度依賴背誦,加劇應(yīng)試教育的傾向,使得應(yīng)聘者更加注重面試通過率而非實際技能的提升。

其實有些八股文是實際遇到問題的經(jīng)驗總結(jié)。

這個問題是我們在線上每日錯誤日志清零時發(fā)現(xiàn)排查的死鎖問題。在這里介紹一下,給大家遇到類似問題時提供一個排查思路。

2 線上問題

2.1 線上異常日志

線上錯誤日志,從日志第2行可以發(fā)現(xiàn)是發(fā)生了死鎖, 從第6行可以發(fā)現(xiàn)是插入了數(shù)據(jù)時發(fā)生了異常, 從20行可以看到異常的方法。

圖片圖片

根據(jù)日志找到業(yè)務(wù)代碼,發(fā)現(xiàn)業(yè)務(wù)代碼邏輯是:先把回收單id 對應(yīng) 歷史的回收單都更新為失效,然后再插入回收單id對應(yīng)的新的回收單數(shù)據(jù)。

2.2 數(shù)據(jù)準備

首先在測試庫里建表,并準備相關(guān)的原數(shù)據(jù)。1、使用的mysql版本:線上5.7.21,測試8.0.322、配置的隔離級別:REPEATABLE-READ 創(chuàng)建個checkout_detail表,分別插入三條數(shù)據(jù)。

CREATE TABLE `checkout_detail` (
  `id` bigint(20) NOT NULL COMMENT '主鍵id',
  `recycle_order_id` bigint(20) NOT NULL COMMENT '回收單ID',
  `confirm_recycle_time` datetime NOT NULL COMMENT '確認回收時間',
  `contrast_type` int(4) NOT NULL COMMENT '對比類型:1:售前、2:后驗、3:售后',
  `remark` varchar(255) DEFAULT '' COMMENT '備注',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_idx_recycle_order_id_contrast_type` (`recycle_order_id`,`contrast_type`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后驗詳情表';
 
INSERT INTO checkout_detail ( id, recycle_order_id, confirm_recycle_time, contrast_type, remark )
VALUES
 ( 1, 1, '2024-07-15 19:56:01', 1, "回收單1" );#模擬線上數(shù)據(jù)
 INSERT INTO checkout_detail ( id, recycle_order_id, confirm_recycle_time, contrast_type, remark );
VALUES
 ( 2, 10, '2024-07-15 19:56:01', 2, "回收單10" );#模擬線上數(shù)據(jù)
 INSERT INTO checkout_detail ( id, recycle_order_id, confirm_recycle_time, contrast_type, remark );
VALUES
 ( 3, 20, '2024-07-15 19:56:01', 3, "回收單20" ); #模擬線上數(shù)據(jù)

2.3 問題復(fù)現(xiàn)

2.3.1 執(zhí)行流程

執(zhí)行時間順序

事務(wù)A

事務(wù)B


START TRANSACTION;

START TRANSACTION;

1

update checkout_detail SET remark = '更新狀態(tài)' WHERE recycle_order_id = 30;


2


update checkout_detail SET remark = '更新狀態(tài)' WHERE recycle_order_id = 40;

3

INSERT INTO checkout_detail ( id, recycle_order_id, confirm_recycle_time, contrast_type, remark )VALUES( 30, 30, '2024-07-15 19:56:01', 1, "插入回收單30" );


4


INSERT INTO checkout_detail ( id, recycle_order_id, confirm_recycle_time, contrast_type, remark )VALUES( 40, 40, '2024-07-15 19:56:01', 1, "插入回收單40" );

大家可以思考一下,這個執(zhí)行過程中都會加哪些鎖?會發(fā)生鎖等待嗎?會發(fā)生死鎖嗎?

2.3.2 死鎖排查

上面執(zhí)行第3步會鎖等待,執(zhí)行第4步會死鎖。

執(zhí)行如下SQL:

SHOW ENGINE INNODB STATUS;

它是MySQL 中一個非常有用的命令,它用于顯示 InnoDB 存儲引擎的當前狀態(tài)信息。這個命令對于診斷 InnoDB 存儲引擎的問題、監(jiān)控性能以及理解內(nèi)部操作非常有幫助。

輸出的內(nèi)容非常多,我們只關(guān)注鎖信息就行,找到LATEST DETECTED DEADLOCK 最近一次死鎖信息如下:

圖片圖片

2.3.3 死鎖日志分析

現(xiàn)在讓我們來分析這個死鎖日志,我只會分析我們需要的信息。

2.3.3.1 事務(wù)A23087信息

*** (1) "TRANSACTION":<br/>
TRANSACTION 23087, ACTIVE 22 sec inserting<br/>
mysql tables in use 1, locked 1<br/>
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 1<br/>
MySQL thread id 9, OS thread handle 123145459134464, query id 1039 localhost 127.0.0.1 root update<br/>
INSERT INTO checkout_detail ( id, recycle_order_id, confirm_recycle_time, contrast_type, remark )VALUES( 30, 30, '2024-07-15 "19":56:01', 1, "插入回收單30" )<br/>
  1. 事務(wù)狀態(tài) 事務(wù)ID:23087 操作:正在進行插入(INSERT)操作。
  2. 鎖等待情況 鎖結(jié)構(gòu)數(shù)量:3個鎖結(jié)構(gòu),這表明MySQL為該事務(wù)準備了多個鎖來管理對數(shù)據(jù)的訪問。行鎖數(shù)量:2個行鎖,說明事務(wù)試圖在checkout_detail表中的兩行數(shù)據(jù)上設(shè)置鎖。
  3. 事務(wù)阻塞 LOCK WAIT:這表明事務(wù)正在等待其他事務(wù)釋放鎖。在當前情況下,它正在等待能夠插入或更新它試圖操作的兩行數(shù)據(jù)。

2.3.3.2 事務(wù)23087持有鎖

*** (1) HOLDS THE "LOCK(S)":<br/>
RECORD LOCKS space id 4 page no 5 n bits 72 index uniq_idx_recycle_order_id_contrast_type of table `my_database`.`checkout_detail` trx id 23087 lock_mode X <br/>
Record lock, heap no 1 PHYSICAL "RECORD": n_fields 1; compact format; info bits 0<br/>
 "0": len 8; hex 73757072656d756d; asc supremum;;<br/>

事務(wù)23087持有的鎖是一個針對uniq_idx_recycle_order_id_contrast_type索引的X(排他)鎖,但它實際上鎖定的是索引中的“supremum”偽記錄。這通常意味著事務(wù)并沒有鎖定任何具體的、存在的數(shù)據(jù)行,而是鎖定了一個表示索引末尾的虛擬記錄。

2.3.3.3 事務(wù)23087等待鎖

*** (1) WAITING FOR THIS LOCK TO BE "GRANTED":<br/>
RECORD LOCKS space id 4 page no 5 n bits 72 index uniq_idx_recycle_order_id_contrast_type of table `my_database`.`checkout_detail` trx id 23087 lock_mode X insert intention waiting<br/>
Record lock, heap no 1 PHYSICAL "RECORD": n_fields 1; compact format; info bits 0<br/>
 "0": len 8; hex 73757072656d756d; asc supremum;;<br/>

事務(wù)23087正在等待一個插入意向鎖(lock_mode X insert intention waiting)被授予

2.3.3.4 事務(wù)23088信息

** (2) "TRANSACTION":
TRANSACTION 23088, ACTIVE 14 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 1
MySQL thread id 10, OS thread handle 123145460199424, query id 1043 localhost 127.0.0.1 root update
INSERT INTO checkout_detail ( id, recycle_order_id, confirm_recycle_time, contrast_type, remark )VALUES( 40, 40, '2024-07-15 "19":56:01', 1, "插入回收單40" )
  1. 事務(wù)狀態(tài) 事務(wù)ID:23088 操作:正在進行插入(INSERT)操作。
  2. 鎖等待情況 鎖結(jié)構(gòu)數(shù)量:3個鎖結(jié)構(gòu),這表明MySQL為該事務(wù)準備了多個鎖來管理對數(shù)據(jù)的訪問。行鎖數(shù)量:2個行鎖,說明事務(wù)試圖在checkout_detail表中的兩行數(shù)據(jù)上設(shè)置鎖。
  3. 事務(wù)阻塞 LOCK WAIT:這表明事務(wù)正在等待其他事務(wù)釋放鎖。在當前情況下,它正在等待能夠插入或更新它試圖操作的兩行數(shù)據(jù)。

2.3.3.5 事務(wù)23088持有鎖

*** (2) HOLDS THE "LOCK(S)":
RECORD LOCKS space id 4 page no 5 n bits 72 index uniq_idx_recycle_order_id_contrast_type of table `my_database`.`checkout_detail` trx id 23088 lock_mode X
Record lock, heap no 1 PHYSICAL "RECORD": n_fields 1; compact format; info bits 0
 "0": len 8; hex 73757072656d756d; asc supremum;;

事務(wù)23088持有的鎖是一個針對uniq_idx_recycle_order_id_contrast_type索引的X(排他)鎖,但它實際上鎖定的是索引中的“supremum”偽記錄。這通常意味著事務(wù)并沒有鎖定任何具體的、存在的數(shù)據(jù)行,而是鎖定了一個表示索引末尾的虛擬記錄。

2.3.3.6 事務(wù)23088等待鎖

*** (2) WAITING FOR THIS LOCK TO BE "GRANTED":
RECORD LOCKS space id 4 page no 5 n bits 72 index uniq_idx_recycle_order_id_contrast_type of table `my_database`.`checkout_detail` trx id 23088 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL "RECORD": n_fields 1; compact format; info bits 0
 "0": len 8; hex 73757072656d756d; asc supremum;;

事務(wù)23088正在等待一個插入意向鎖(lock_mode X insert intention waiting)被授予

3 分析原因

參考MySQL的官方文檔。

間隙鎖(Gap Locks)是一種特殊的鎖機制,用于鎖定索引記錄之間的間隙,或者第一個索引記錄之前的間隙以及最后一個索引記錄之后的間隙。這種鎖的主要目的是防止其他事務(wù)在這些間隙中插入新的記錄,從而維護數(shù)據(jù)的一致性和隔離性。

插入意向鎖(Insert Intention Locks) 是InnoDB存儲引擎在插入操作前設(shè)置的一種間隙鎖(Gap Locks)。這種鎖的目的是在多個事務(wù)嘗試向同一個索引間隙中插入不同位置的數(shù)據(jù)時,能夠并行執(zhí)行而不需要相互等待。

可以得到索引如下加鎖示意圖

索引上添加鎖索引上添加鎖

鎖總是鎖定索引記錄。如果要鎖定的是最后一條記錄之后的區(qū)間,防止有人在這個區(qū)間插入數(shù)據(jù),那么mysql就會鎖定隱藏的最大記錄

索引記錄關(guān)聯(lián)的鎖索引記錄關(guān)聯(lián)的鎖

4 解決方法

1、查看死鎖日志時,先看一下發(fā)生死鎖的事務(wù)等待獲取鎖的語句, 都有哪些語句發(fā)生死鎖。

2、根據(jù)死鎖語句,找到相關(guān)到業(yè)務(wù)代碼(如果有日志,直接根據(jù)日志找到業(yè)務(wù)代碼也行)。

3、根據(jù)業(yè)務(wù)代碼執(zhí)行流程,來分析死鎖發(fā)生過程。(注意分析數(shù)據(jù)存在,數(shù)據(jù)不存在時的加鎖區(qū)別)

發(fā)現(xiàn)了問題原因,那么解決方案就很簡單了。在這個場景下是:先查詢數(shù)據(jù)是否存在,如果數(shù)據(jù)存在則更新,如果數(shù)據(jù)不存在再插入。

5 總結(jié)

  • 兩個事務(wù)即使生成的間隙鎖的范圍是一樣的,也不會發(fā)生沖突,因為間隙鎖目的是為了防止其他事務(wù)插入數(shù)據(jù),因此間隙鎖與間隙鎖之間是相互兼容的。
  • 在執(zhí)行插入語句時,如果插入的記錄在其他事務(wù)持有間隙鎖范圍內(nèi),插入語句就會被阻塞,因為插入語句在碰到間隙鎖時,會生成一個插入意向鎖,然后插入意向鎖和間隙鎖之間是互斥的關(guān)系。
責(zé)任編輯:武曉燕 來源: 轉(zhuǎn)轉(zhuǎn)技術(shù)
相關(guān)推薦

2023-06-14 08:34:18

Mybatis死鎖框架

2021-03-28 09:12:58

多線程死鎖技術(shù)熱點

2024-11-20 08:00:00

死鎖多線程編程

2025-01-20 13:20:00

MySQL數(shù)據(jù)遷移數(shù)據(jù)庫

2021-07-05 22:11:38

MySQL體系架構(gòu)

2017-06-07 16:10:24

Mysql死鎖死鎖日志

2022-01-02 08:43:46

Python

2024-01-19 08:25:38

死鎖Java通信

2021-06-09 19:23:52

MySQLROLE管理

2021-07-02 09:45:29

MySQL InnoDB數(shù)據(jù)

2021-07-06 08:59:18

抽象工廠模式

2023-01-03 08:31:54

Spring讀取器配置

2023-11-28 08:29:31

Rust內(nèi)存布局

2022-08-26 09:29:01

Kubernetes策略Master

2021-05-11 08:54:59

建造者模式設(shè)計

2022-08-23 08:00:59

磁盤性能網(wǎng)絡(luò)

2022-02-07 11:01:23

ZooKeeper

2022-08-04 15:31:45

MySQL加鎖機制死鎖

2021-12-07 08:50:40

字母區(qū)間字符串

2021-07-29 07:55:20

React實踐代碼
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 少妇性l交大片免费一 | 91久久久久久久久久久 | 久久狠狠| 99小视频| 久久久久中文字幕 | 日韩成人国产 | 免费视频一区二区三区在线观看 | 日韩在线欧美 | 国产清纯白嫩初高生在线播放视频 | 成人午夜视频在线观看 | 欧美成人专区 | 2019天天干天天操 | 日韩视频一区二区 | 日韩aⅴ视频 | 亚洲国产一区二区三区四区 | 国产精品一区二区av | 中文字幕日韩av | 夜夜摸天天操 | 做a视频在线观看 | 在线观看精品视频网站 | 91麻豆精品国产91久久久更新资源速度超快 | 雨宫琴音一区二区在线 | 国产一级片91 | 日韩欧美一区二区三区四区 | 欧美精品乱码久久久久久按摩 | 国产激情视频网 | 中文字幕在线观看日韩 | 久久国产精品精品 | 欧美视频网 | 国产成人综合av | 91精品国产91综合久久蜜臀 | 亚洲精品乱码久久久久久按摩观 | 日韩 欧美 二区 | 日日摸日日碰夜夜爽亚洲精品蜜乳 | 琪琪午夜伦伦电影福利片 | www国产成人免费观看视频 | 黄色成人在线观看 | 三级成人片| 国产精品免费观看 | 欧美成人h版在线观看 | 免费在线观看av网址 |