日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

          歡迎訪問 生活随笔!

          生活随笔

          當前位置: 首頁 > 运维知识 > 数据库 >内容正文

          数据库

          MySQL死锁案例分:先delete,再insert,导致死锁

          發(fā)布時間:2024/1/17 数据库 27 豆豆
          生活随笔 收集整理的這篇文章主要介紹了 MySQL死锁案例分:先delete,再insert,导致死锁 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

          一、死鎖案例

          MySQL版本:Percona MySQL Server 5.7.19
          隔離級別:可重復讀(RR)
          業(yè)務邏輯:并發(fā)下按某個索引字段先delete記錄,再insert記錄

          比如:

          begin; delete from tb where order_id = xxx; insert into tb(order_id) values(xxx); commit;

          二、MySQL鎖基本概念

          S:共享鎖(行級鎖)
          X:排他鎖(行級鎖)
          IS:意向共享鎖(表級鎖)
          IX:意向排他鎖(表級鎖)

          以上4種鎖的兼容性見下表:


          鎖模式兼容性表

          • gap鎖與gap鎖之間不沖突
          • rec insert intention(插入意向鎖)與gap鎖沖突。

          三、模擬復現(xiàn)死鎖

          打開參數(shù),從innodb status獲取更多的鎖信息。
          set GLOBAL innodb_status_output_locks=ON;

          表結構:

          CREATE TABLE `tb` (`order_id` int(11) DEFAULT NULL,KEY `idx_order_id` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

          表中數(shù)據(jù):

          mysql> select * from tb; +----------+ | order_id | +----------+ | 10 | | 20 | +----------+ 2 rows in set (0.00 sec)

          事務執(zhí)行步驟:

          session1session2
          begin?
          ?begin
          delete from tb where order_id=15;?
          ?delete from tb where order_id=15;
          ?insert into tb select 15;(等待鎖)
          insert into tb select 15;(死鎖)?
        1. 當session1執(zhí)行delete from tb where order_id=15;,由于條件order_id=15的記錄不存在,session1 獲得2個鎖結構,分別是意向排他鎖IX(表級鎖)、gap鎖(行級鎖),如下:
        2. ---TRANSACTION 1055191443, ACTIVE 20 sec 2 lock struct(s), heap size 1136, 1 row lock(s) MySQL thread id 315642, OS thread handle 139960342456064, query id 150462030 localhost root TABLE LOCK table `db`.`tb` trx id 1055191443 lock mode IX RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191443 lock_mode X locks gap before rec
        3. 當session2執(zhí)行delete from tb where order_id=15;,同樣由于order_id=15的記錄不存在,session2 也獲得2個鎖結構,分別是意向排他鎖IX(表級鎖)、gap鎖(行級鎖),如下:
        4. ---TRANSACTION 1055191444, ACTIVE 3 sec 2 lock struct(s), heap size 1136, 1 row lock(s) MySQL thread id 315336, OS thread handle 139960562685696, query id 150462412 localhost root TABLE LOCK table `db`.`tb` trx id 1055191444 lock mode IX RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec
        5. 當session2執(zhí)行insert into tb select 15;, session2 已經(jīng)獲取到IX鎖,gap鎖,等待 rec insert intention(插入意向鎖)
        6. ---TRANSACTION 1055191444, ACTIVE 68 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 315336, OS thread handle 139960562685696, query id 150462778 localhost root executing insert into tb select 15 ------- TRX HAS BEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec insert intention waiting ------------------ TABLE LOCK table `db`.`tb` trx id 1055191444 lock mode IX RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec insert intention waiting
        7. 當session1執(zhí)行insert into tb select 15;,session1 已獲取到IX鎖,gap鎖, 等待rec insert intention(插入意向鎖), session1, session2 都在等待插入意向鎖, 插入意向鎖與gap鎖沖突,雙方都沒有釋放gap鎖,又都在等待插入意向鎖,死鎖發(fā)生。
        8. LATEST DETECTED DEADLOCK ------------------------ 2018-11-03 17:15:11 0x7f4b0e7ea700 *** (1) TRANSACTION: TRANSACTION 1055191444, ACTIVE 135 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 315336, OS thread handle 139960562685696, query id 150462778 localhost root executing insert into tb select 15 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec insert intention waiting *** (2) TRANSACTION: TRANSACTION 1055191443, ACTIVE 201 sec inserting, thread declared inside InnoDB 5000 mysql tables in use 1, locked 1 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 315642, OS thread handle 139960342456064, query id 150463172 localhost root executing insert into tb select 15 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191443 lock_mode X locks gap before rec *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191443 lock_mode X locks gap before rec insert intention waiting *** WE ROLL BACK TRANSACTION (2)

          四、案例擴展

          以上死鎖案例,業(yè)務代碼邏輯是多線程并發(fā)下,有可能多個線程會執(zhí)行相同order_id的job,比如兩個線程執(zhí)行的order_id 都是15。
          另外一種情況,多個線程間,不會執(zhí)行到相同order_id的情況,也可能發(fā)生死鎖。比如一個線程order_id=15,另外一個線程order_id=16,如下所示:

          事務執(zhí)行步驟:

          session1session2
          begin?
          ?begin
          delete from tb where order_id=15;?
          ?delete from tb where order_id=16;
          ?insert into tb select 16;(等待鎖)
          insert into tb select 15;(死鎖)?

          鎖情況與上述相同,不再贅述,死鎖信息如下:

          LATEST DETECTED DEADLOCK ------------------------ 2018-11-03 17:28:30 0x7f4b0e667700 *** (1) TRANSACTION: TRANSACTION 1055191450, ACTIVE 18 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 316221, OS thread handle 139960338228992, query id 150467652 localhost root executing insert into tb select 16 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191450 lock_mode X locks gap before rec insert intention waiting *** (2) TRANSACTION: TRANSACTION 1055191449, ACTIVE 28 sec inserting, thread declared inside InnoDB 5000 mysql tables in use 1, locked 1 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 316222, OS thread handle 139960340870912, query id 150467681 localhost root executing insert into tb select 15 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191449 lock_mode X locks gap before rec *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191449 lock_mode X locks gap before rec insert intention waiting *** WE ROLL BACK TRANSACTION (2)

          五、解決方案

        9. 修改隔離級別為提交讀(RC)
        10. 修改業(yè)務代碼邏輯,刪除記錄之前,先select,確認該記錄存在,再執(zhí)行delete刪除該記錄。
        11. 總結

          以上是生活随笔為你收集整理的MySQL死锁案例分:先delete,再insert,导致死锁的全部內容,希望文章能夠幫你解決所遇到的問題。

          如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。