问题发现现场:
最近系统中经常报锁相关的异常:
如下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