文章导航-readme

MySql 更新死锁问题 Deadlock found when trying to get lock; try restarting transaction

1.场景

//table1
CREATE TABLE `retailtrades` (
`TradeId` bigint(20) NOT NULL COMMENT '主键',
`TradeCode` varchar(20) NOT NULL COMMENT '交易单号',
`TradeAmount` decimal(14,4) NOT NULL COMMENT '交易金额',
`CreateTime` datetime NOT NULL COMMENT '创建时间',
`TradeState` tinyint(4) NOT NULL COMMENT '交易状态 1:未支付 2:已支付 3:支付异常',
`SuccessTime` datetime DEFAULT NULL COMMENT '支付成功时间',
PRIMARY KEY (`TradeId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='零售交易单表'; //table2
CREATE TABLE `retailorders` (
`OrderId` bigint(20) NOT NULL COMMENT '主键',
`OrderCode` varchar(20) NOT NULL COMMENT '订单编号',
`CreateTime` datetime NOT NULL COMMENT '创建时间',
`OrderStatus` tinyint(4) NOT NULL COMMENT '1:待付款 2:待确认 3:待发货 4:待收货 5:已完成 6:已取消',
PRIMARY KEY (`OrderId`),
UNIQUE KEY `OrderCode` (`OrderCode`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='零售订单表';
//sql1
update retailtrades set TradeState=2 where TradeCode='111706022040540002'; //sql2
update retailorders set OrderStatus=2 where FIND_IN_SET(ordercode,'111706022040540001'); //提交方式:组装到hashtable内事务提交 //当并发请求时出现问题:
Deadlock found when trying to get lock; try restarting transaction

2.知识点

  1. mysql innodb引擎支持事务,更新时采用的是行级锁。
  2. 行级锁必须建立在索引的基础
  3. 行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。如果操作用到了主键索引会先在主键索引上加锁,然后在其他索引上加锁,否则加锁顺序相反。
  4. 对于没有用索引的操作会采用表级锁
  5. mysql FIND_IN_SET 函数会全表扫描

3.问题分析

  1. table1 TradeCode字段未设置索引 update语句会锁表
  2. table2 OrderCode字段虽设置索引但使用FIND_IN_SET 作为查询条件 也会锁表
  3. 程序采用hashtable组装sql语句,由于hash执行是无序的,若同时并发两个请求事务执行顺序如下:
事务1 事务2
begin TRANSACTION ...
update retailtrades set TradeState=2 where TradeCode='111706022040540002'; begin TRANSACTION
锁住table1等待table2 update retailorders set orderstatus=2 where FIND_IN_SET(ordercode,'111706030019320003');
... 锁住table2等待table1
update retailorders set orderstatus=2 where FIND_IN_SET(ordercode,'111706022040540001'); UPDATE retailtrades set tradestate=2 where tradecode='111706030019320004';
死锁 事务1死锁处理后,事务2获取锁执行成功

4.问题模拟重现

//sql1
start TRANSACTION;
UPDATE retailtrades set tradestate=2 where tradecode='111706022040540002';
select sleep(5);
update retailorders set orderstatus=2 where FIND_IN_SET(ordercode,'111706022040540001');
COMMIT //sql2
start TRANSACTION ;
update retailorders set orderstatus=2 where FIND_IN_SET(ordercode,'111706030019320003');
SELECT sleep(5);
UPDATE retailtrades set tradestate=2 where tradecode='111706030019320004';
COMMIT //于navicat中打开两个窗口先执行sql1,后执行sql2,查看执行结果

5.问题解决

通过以上分析结果问题最简单暴力的解决方式就是讲hashtable组装sql改为有序集合,但此种解决方式并不能解决以上sql与表的性能问题。

因此建议如下:

  1. table1 TradeCode字段 考虑是否增加索引提高查询更新速度,避免更新锁表
  2. sql2 避免使用FIND_IN_SET(注意:FIND_IN_SET会全表扫描,效率低下,查询的时候尽量也不要使用),可改为in
  3. sql组装方式改为有序集合
  4. 建议update语句使用主键索引作为更新条件

6.问题扩展

CREATE TABLE `user_item` (
`id` BIGINT(20) NOT NULL,
`user_id` BIGINT(20) NOT NULL,
`item_id` BIGINT(20) NOT NULL,
`status` TINYINT(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_1` (`user_id`,`item_id`,`status`)
) ENGINE=INNODB DEFAULT CHARSET=utf-8
update user_item set status=1 where user_id=? and item_id=?
  1. 由于用到了非主键索引,首先需要获取idx_1上的行级锁
  2. 紧接着根据主键进行更新,所以需要获取主键上的行级锁;
  3. 更新完毕后,提交,并释放所有锁。
//如果在步骤1和2之间突然插入一条语句:
update user_item .....where id=? and user_id=?
//这条语句会先锁住主键索引,然后锁住idx_1。
//蛋疼的情况出现了,一条语句获取了idx_1上的锁,等待主键索引上的锁;
//另一条语句获取了主键上的锁,等待idx_1上的锁,这样就出现了死锁。

解决方案

//1.先获取需要更新的记录的主键
select id from user_item where user_id=? and item_id=?
//2. 逐条更新
...

MySql 更新死锁问题 Deadlock found when trying to get lock; try restarting transaction的更多相关文章

  1. mysql报ERROR:Deadlock found when trying to get lock; try restarting transaction(nodejs)

    1 前言 出现错误 Deadlock found when trying to get lock; try restarting transaction.然后通过网上查找资料,重要看到有用信息了. 错 ...

  2. mysql - InnoDB存储引擎 死锁问题( Deadlock found when trying to get lock; try restarting transaction )

    刚刚向数据库插入数据的时候出现了这么一段错误 Deadlock found when trying to get lock; try restarting transaction 主要原因(由于无法使 ...

  3. Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

    我在update数据库的时候出现的死锁 数据库表死锁 Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackExcept ...

  4. MySQL error : Deadlock found when trying to get lock; try restarting transaction

    在使用 MySQL 时,我们有时会遇到这样的报错:“Deadlock found when trying to get lock; try restarting transaction”. 在 14. ...

  5. Deadlock found when trying to get lock; try restarting transaction

    1.错误描述 [ERROR:]2015-06-09 16:56:19,481 [抄送失败] org.hibernate.exception.LockAcquisitionException: erro ...

  6. 1213 - Deadlock found when trying to get lock; try restarting transaction

    1213 - Deadlock found when trying to get lock; try restarting transaction 出现这个原因要记住一点就是:innodb的行锁 和解 ...

  7. mysql死锁com.mysql.cj.jdbc.exception.MYSQLTransactionRollbackException Deadlock found when trying to get lock;try restarting transaction

    1.生产环境出现以下报错 该错误发生在update操作中,该表并未建立索引,也就是只有InnoDB默认的主键索引,发生错误的程序是for循环中update. 什么情况下会出现Deadlock foun ...

  8. 数据库死锁的问题,Deadlock found when trying to get lock; try restarting transaction at Query.formatError

    场景: 应用刚上线排除大批量请求的问题 线上多次出现的Deadlock found when trying to get lock错误 代码: async batchUpdate(skus, { tr ...

  9. MySQL更新死锁问题

    作为一个社交类的 App ,我们有很多操作都会同时发生,为了确保数据的一致性,会采用数据库的事物. 比如现在我们有一个点赞操作,点赞成功后,需要更改文章的热度.以下是 SQL 语句: INSERT I ...

随机推荐

  1. 基于webpack实现多html页面开发框架二 css打包、支持scss、文件分离

    本节主要介绍webpack打包的时候CSS的处理方式 一.解决什么问题      1.CSS打包      2.CSS处理浏览器兼容      3.SASS支持      4.CSS分离成单独的文件 ...

  2. 华为ARM64服务器上手体验--不吹不黑,用实际应用来看看TaiShan鲲鹏的表现

    背景 中美贸易冲突以来,相信最大的感受,并不是我对你加多少关税,而是我有,可我不卖给你."禁售"成了市场经济中最大的竞争力. 相信也是因为这个原因,华为"备胎转正&quo ...

  3. docker的安装及常用命令

    一:概述 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器或Windows 机器上,也可以实现虚拟化,容器是完全使用 ...

  4. luogu P1976 鸡蛋饼

    题目背景 Czyzoiers 都想知道小 x 为什么对鸡蛋饼情有独钟.经过一番逼问,小 x 道出了实情:因为他喜欢圆. 题目描述 最近小 x 又发现了一个关于圆的有趣的问题:在圆上有 2N 个不同的点 ...

  5. [译]C#8.0中一个使接口更加灵活的新特性-默认接口实现

    9月份的时候,微软宣布正式发布C#8.0,作为.NET Core 3.0发行版的一部分.C#8.0的新特性之一就是默认接口实现.在本文中,我们将一起来聊聊默认接口实现. 众所周知,对现有应用程序的接口 ...

  6. mac查看开关机记录-last命令

    命令 last | grep reboot (查看开机时间记录) last | grep shutdown (查看关机时间记录) /var/log/messages日志中查询reboot(系统重启) ...

  7. BZOJ 3107 [cqoi2013]二进制a+b (DP)

    3107: [cqoi2013]二进制a+b Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 995  Solved: 444[Submit][Stat ...

  8. Docker系列-(1) 原理与基本操作

    Docker是一个开源的应用容器引擎,基于Go语言,并遵从Apache2.0协议开源. Docker可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的Linux机器 ...

  9. isensor app kit 之 CF5642V2 OV5642 测试总结

    . 总结; 使用官哥的cf5642c-v2时,需要将isensor app kit 上的iic上拉电阻去掉,否则可能导致寄存器初始化不成功,去掉即可,使用柴草电子的模组则不需要.

  10. 介绍一款自己实现的rabbit轻量级组件和使用方法

    DotNetCore.RabbitMQ.Extensions介绍 这是一个 基于.NETStandard 2.0的Rabbit轻量级框架,可以让开发人员无需关注底层变动,专注编写业务代码,从而达到便捷 ...