問題發現現場:
最近系統中經常報鎖相關的異常:
如下sql:
192.168.100.110-3307 lock information:blocked sql:update `recruit_offer` set `remark` = NULL, `mismatch` = 2, `updated_at` = '2020-07-20 14:09:26' where `offer_id` = 3468 blocking sql:update `recruit_offer` set `remark` = NULL, `mismatch` = 2, `updated_at` = '2020-07-20 14:09:26' where `offer_id` = 3468
192.168.100.110-3307 lock information:blocked sql:insert into `recruit_step` (`tob_position_id`, `tob_resume_id`, `step_status`, `step_type`, `uid`, `top_id`, `resume_id`, `deliver_source`, `stage_id`, `stage_type_id`, `source_id`, `hr_status`, `stage_id_from`, `transfer_stage_at`, `stage_type_from`, `updated_at`, `created_at`) values (500, '1886470119214284864', 1, 0, 54429, 2496668, 500, 96, 3, 2, 708, 0, 0, '2020-07-19 09:57:17', 0, '2020-07-19 09:57:17', '2020-07-19 09:57:17') blocking sql:None
線上看到的主要就是這兩種問題.
分析:
1.造成mysql鎖的常見情況:
執行DML操作沒有commit,再執行刪除操作就會鎖表;
在同一事務內先后對同一條數據進行插入和更新操作;
表索引設計不當,導致數據庫出現死鎖;
長事物,阻塞DDL,繼而阻塞所有同表的后續操作;
多台服務器操作同一數據庫;
瞬時出現高並發現象;
事務中存在慢查詢;
事務中嵌套事務或者事務中依賴第三方接口導致事務時間超過默認配置值;
2.本現場出現的原因:
跟運維溝通后發現不是慢查詢,鎖超時時間是系統默認的50秒(正常的業務邏輯已經足夠,其他業務線很少出現類似鎖異常),因此大概率不是服務配置原因,就去查看代碼邏輯吧;
找了很久(業務代碼邏輯很復雜)才發現主要有兩個原因:
(1)同一個事務中對同一條數據有兩次更新(會導致更新時鎖異常)-------同一條數據的更新放在一個操作里面,不要寫成兩條sql
(2)用戶端批量操作且事務邏輯比較長,用戶端看到的現狀是操作很慢導致用戶多次提交(會導致插入時鎖異常)-----優化交互,優化后端代碼邏輯,把非主要的邏輯放在事務外面或者用異步的方式處理,或者最暴力的方法,去掉事務(前提是數據不一致對業務影響不大)
3.總結:
事務中的代碼業務邏輯不要太長(或者嵌套的方法太多),繞來繞去很容易導致事務超時或者增刪改了同一條sql;代碼邏輯主次要分清。(事務中的邏輯盡量短小,需要請求其他三方平台的接口可考慮異步化)
相關連接:
MySql Lock wait timeout exceeded該如何處理?https://www.cnblogs.com/guanbin-529/p/10993549.html