mysql replace into死锁

文章描述了一次生产环境中MapReduce任务的定时调度执行遇到死锁的问题,分析了死锁形成的原因,即两个会话并发操作InnoDB表中唯一键导致的锁竞争。给出了三种解决方案:使用insertignoreinto避免重复插入,采用分布式锁实现串行化,以及考虑使用delete然后批量插入的replaceinto方式。
摘要由CSDN通过智能技术生成

生产环境一个定时调度执行报错,错误日志提示有死锁,mysql版本5.7,本地测试8.0版本不会有问题
了解到该任务采用的是mapreduce模式,存在并行执行的可能。于是在本地测试了一下,果然存在死锁。

测试数据准备

CREATE TABLE `cf_finance_mapping_set_check_model` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `mapping_set_name` varchar(128) DEFAULT NULL COMMENT '静态映射名称',
  `mapping_set_value` varchar(512) DEFAULT NULL COMMENT '静态映射明细',
  `remark` varchar(128) DEFAULT NULL COMMENT '备注',
  `scope_code` varchar(128) NOT NULL COMMENT '核算范围编码',
  `fee_type` varchar(128) NOT NULL COMMENT '费用类型',
  `node` varchar(64) NOT NULL COMMENT '核算节点',
  `run_period` varchar(32) NOT NULL COMMENT '运行期间',
  `account_period` varchar(32) NOT NULL COMMENT '会计期间',
  `tenant` varchar(128) NOT NULL COMMENT '租户',
  `extend_info` varchar(1024) DEFAULT '' COMMENT '扩展信息',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_unique_mapping_idx` (`mapping_set_name`,`mapping_set_value`(128),`scope_code`(64),`fee_type`(64),`node`,`run_period`,`account_period`)
)

会话1执行:执行成功

在这里插入图片描述

会话2执行:执行被阻塞

在这里插入图片描述

会话1再执行:发生死锁

在这里插入图片描述

原因分析

1,会话1第一次replace into 插入,给唯一键加X(独占)锁。
2,会话2replace into插入,唯一键冲突了,给唯一键加S(共享)锁wait。
3,会话1再次replace into 插入,唯一键冲突,给唯一键加S(共享),这时候S锁已经被会话2占有,会话1需要等待会话2释放S锁,会话2需要等待会话1释放X锁,死锁构成。

解决方案

1,用insert ignore into 替换 replace into,在插入相同唯一键时直接忽略不进行插入。
2,用分布式锁将链路改成串行。
3,replace into 改成先删除,再批量插入。

官网说明

InnoDB中不同SQL语句设置的锁

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值