系統中出現死鎖的日誌以下:mysql
*** (1) TRANSACTION: TRANSACTION 1331088253, ACTIVE 0 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 7 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 4 MySQL thread id 14699751, OS thread handle 0x7fc5eaeda700, query id 382901670 172.18.140.10 bms update INSERT INTO `finance_settlement_detail` (`order_detail_id`, `tenant_id`, `store_id`, `order_id`, `working_type_id`, `working_item_id`, `working_item_base_id`, `working_type_name`, `item_code_all`, `achievements_code`, `price_code`, `item_name_all`, `copies_num`, `one_copies_num`, `show_copies_num`, `unit_num`, `unit_price`, `discount`, `amount`, `standard_unit_price`, `standard_total_price`, `item_code1`, `item_name1`, `item_code2`, `item_name2`, `item_code3`, `item_name3`, `item_code4`, `item_name4`, `item_code5`, `item_name5`, `make_info`, `material_id`, `material_name`, `cost_price`, `cost_amount`, `unit`, `make_order_id`, `complete_num`, `outsourcing`, `create_time`, `customer_hash`, `settlement_hash`, `rate`, `product_name`, `below_lowest_price`, `item_lowest_price`, `type_lowest_discount`, `finance_settlement_id`) VALUES (1236472, 125, 1046, 451483, 655, 54047, NULL, '設計/影像', 'custom', NUL *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1156 page no 24892 n bits 760 index `finance_settlement_id` of table `test`.`finance_settlement_detail` trx id 1331088253 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;; *** (2) TRANSACTION: TRANSACTION 1331088264, ACTIVE 0 sec inserting mysql tables in use 1, locked 1 7 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 4 MySQL thread id 14699754, OS thread handle 0x7fc5eacd2700, query id 382901673 172.18.140.10 bms update INSERT INTO `finance_settlement_detail` (`order_detail_id`, `tenant_id`, `store_id`, `order_id`, `working_type_id`, `working_item_id`, `working_item_base_id`, `working_type_name`, `item_code_all`, `achievements_code`, `price_code`, `item_name_all`, `copies_num`, `one_copies_num`, `show_copies_num`, `unit_num`, `unit_price`, `discount`, `amount`, `standard_unit_price`, `standard_total_price`, `item_code1`, `item_name1`, `item_code2`, `item_name2`, `item_code3`, `item_name3`, `item_code4`, `item_name4`, `item_code5`, `item_name5`, `make_info`, `material_id`, `material_name`, `cost_price`, `cost_amount`, `unit`, `make_order_id`, `complete_num`, `outsourcing`, `create_time`, `customer_hash`, `settlement_hash`, `rate`, `product_name`, `below_lowest_price`, `item_lowest_price`, `type_lowest_discount`, `finance_settlement_id`) VALUES (1247931, 118, 240, 455597, 961, 115484, 40698, '彩色快印', 'csdy a4dm 80 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 1156 page no 24892 n bits 760 index `finance_settlement_id` of table `test`.`finance_settlement_detail` trx id 1331088264 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;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1156 page no 24892 n bits 760 index `finance_settlement_id` of table `test`.`finance_settlement_detail` trx id 1331088264 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;; *** WE ROLL BACK TRANSACTION (2) 2018-10-26 12:21:54 7fc5eaf5c700InnoDB: transactions deadlock detected, dumping detailed information. 2018-10-26 12:21:54 7fc5eaf5c700
死鎖日誌分析:sql
一、事務1執行insert語句等待得到X鎖;工具
二、事務2現持有S鎖,但執行insert語句也在等待X鎖,這樣就存在兩個事務間相互等待,死鎖產生,Mysql自動回滾了事務2;spa
三、表引擎爲innodb,行鎖,在字段finance_settlement_id造成,普通索引而非主鍵索引;debug
四、由於Mysql死鎖日誌打印不徹底,沒法知道上文死鎖產生前的sql語句的執行狀況,根據以上還沒法徹底分析出死鎖產生的根本緣由。設計
根據使用Xdebug工具進一步調試跟蹤代碼執行狀況,發如今死鎖前有update finance_settlement_detail where finance_settlement_Id = XXX這樣的語句,這應該就是死鎖產生的」兇手「了。調試
最終緣由分析:日誌
一、innodb引擎下update在默認狀況下是行鎖,可是在Mysql默認隔離級別(可重複讀)下,一旦update更新的數據行不存在,則會產生間隙鎖(Gap lock);code
二、事務1 update不存在的數據行,產生了Gap lock,事務2 update不存在的數據行,也產生了Gap lock;orm
三、事務1 insert操做須要等待對方釋放X鎖,事務2 insert操做也須要等待對方釋放X鎖,死鎖產生,Mysql自動回滾了事務2;
如何解決死鎖:
解決死鎖的原則就是破壞死鎖產生的條件,在以上案例中,只須要判斷當對應數據行不存在時,不執行update語句便可。