MySql 更新死锁问题 Deadlock found when trying to get lock; try restarting transaction
文章导航-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.知识点
- mysql innodb引擎支持事务,更新时采用的是行级锁。
- 行级锁必须建立在索引的基础
- 行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。如果操作用到了主键索引会先在主键索引上加锁,然后在其他索引上加锁,否则加锁顺序相反。
- 对于没有用索引的操作会采用表级锁
- mysql FIND_IN_SET 函数会全表扫描
3.问题分析
- table1 TradeCode字段未设置索引 update语句会锁表
- table2 OrderCode字段虽设置索引但使用FIND_IN_SET 作为查询条件 也会锁表
- 程序采用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与表的性能问题。
因此建议如下:
- table1 TradeCode字段 考虑是否增加索引提高查询更新速度,避免更新锁表
- sql2 避免使用FIND_IN_SET(注意:FIND_IN_SET会全表扫描,效率低下,查询的时候尽量也不要使用),可改为in
- sql组装方式改为有序集合
- 建议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=?
- 由于用到了非主键索引,首先需要获取idx_1上的行级锁
- 紧接着根据主键进行更新,所以需要获取主键上的行级锁;
- 更新完毕后,提交,并释放所有锁。
//如果在步骤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的更多相关文章
- mysql报ERROR:Deadlock found when trying to get lock; try restarting transaction(nodejs)
1 前言 出现错误 Deadlock found when trying to get lock; try restarting transaction.然后通过网上查找资料,重要看到有用信息了. 错 ...
- mysql - InnoDB存储引擎 死锁问题( Deadlock found when trying to get lock; try restarting transaction )
刚刚向数据库插入数据的时候出现了这么一段错误 Deadlock found when trying to get lock; try restarting transaction 主要原因(由于无法使 ...
- 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 ...
- MySQL error : Deadlock found when trying to get lock; try restarting transaction
在使用 MySQL 时,我们有时会遇到这样的报错:“Deadlock found when trying to get lock; try restarting transaction”. 在 14. ...
- Deadlock found when trying to get lock; try restarting transaction
1.错误描述 [ERROR:]2015-06-09 16:56:19,481 [抄送失败] org.hibernate.exception.LockAcquisitionException: erro ...
- 1213 - Deadlock found when trying to get lock; try restarting transaction
1213 - Deadlock found when trying to get lock; try restarting transaction 出现这个原因要记住一点就是:innodb的行锁 和解 ...
- mysql死锁com.mysql.cj.jdbc.exception.MYSQLTransactionRollbackException Deadlock found when trying to get lock;try restarting transaction
1.生产环境出现以下报错 该错误发生在update操作中,该表并未建立索引,也就是只有InnoDB默认的主键索引,发生错误的程序是for循环中update. 什么情况下会出现Deadlock foun ...
- 数据库死锁的问题,Deadlock found when trying to get lock; try restarting transaction at Query.formatError
场景: 应用刚上线排除大批量请求的问题 线上多次出现的Deadlock found when trying to get lock错误 代码: async batchUpdate(skus, { tr ...
- MySQL更新死锁问题
作为一个社交类的 App ,我们有很多操作都会同时发生,为了确保数据的一致性,会采用数据库的事物. 比如现在我们有一个点赞操作,点赞成功后,需要更改文章的热度.以下是 SQL 语句: INSERT I ...
随机推荐
- php踩过的那些坑(5)浮点数计算
一.前方有坑 php在使用加减乘除等运算符计算浮点数的时候,经常会出现意想不到的结果,特别是关于财务数据方面的计算,给不少工程师惹了很多的麻烦.比如今天工作终于到的一个案例: $a = 2586; $ ...
- uni-app之网络请求
uni-app之网络请求 一,介绍 uni.request(OBJECT),发起网络请求,以下主要是一些特殊的参数说明,详细的可查看uni-app官网. 1,method的有效值必须是大写,默认GET ...
- 挑战10个最难的Java面试题(附答案)【上】
欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),验证通过后,输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动&quo ...
- Java修炼——线程同步的俩种方法
当多线程去同时抢占CPU资源时,有多线程的安全问题.这时候就需要将线程同步.线程同步有俩个方法. 1.同步代码块(synchronize),同步代码块需要同步监视器,同步监视器是针对对象进行操作.什么 ...
- Spring Boot缓存Ehcache
Spring Boot 整合 Ehcache 修改 pom 文件 <!-- Spring Boot 缓存支持启动器 --> <dependency> <groupId ...
- PHP原生实现简易的MVC框架
目录结构: —|controller —|Home.php —|model —|view —|welcome.php —|index.php 基本原理: 首页 index.php 通过获得地址栏中的路 ...
- Matlab Robotics Toolbox 仿真计算:Kinematics, Dynamics, Trajectory Generation
1. 理论知识 理论知识请参考: 机器人学导论++(原书第3版)_(美)HLHN+J.CRAIG著++贠超等译 机器人学课程讲义(丁烨) 机器人学课程讲义(赵言正) 2. Matlab Robotic ...
- Java并发编程系列-(6) Java线程池
6. 线程池 6.1 基本概念 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理.如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题:如果并发的请求数 ...
- 知识图谱推理与实践(3) -- jena自定义builtin
在第2篇里,介绍了jena的The general purpose rule engine(通用规则引擎)及其使用,本篇继续探究,如何自定义builtin. builtin介绍 先回顾builtin为 ...
- centos安装与配置keepalived+nginx高可用
一.安装启动keepalived 1.下载keepalived 在centos系统中,用wget下载最新版本: mkdir tool cd tool wget https://www.keepaliv ...