问题描述

在生产中有两笔单子同时进行 ,一个是新增一个是修改操作,且这两个操作都通过spring添加了事务,由于死锁导致了新增的这笔单子新增失败导致回滚。
记录一次生产情况下出现mysql死锁

解决思路

1、先使用 >SHOW ENGINE INNODB STATUS 命令查看了mysql的最近一次死锁记录
记录一次生产情况下出现mysql死锁

记录一次生产情况下出现mysql死锁
记录一次生产情况下出现mysql死锁
2、分析后得到结论由于两个事务的执行语句顺序相反,应该是先修改table1 再修改table2,另一个是先修改table2再修改table1导致两个资源都在对方手里,数据库只能回滚事务1来解决死锁问题。
3、提出问题:mysql数据库当时我们设置的存储引擎是InnoDB 应该是行锁级别的,为何两个语句涉及修改的行不一样也会发生被锁的情况。 在一番查找后发现,原来数据类型的转换导致索引失效。

在 Mysql 中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql 语句操作了主键索引,Mysql
就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。 InnoDB
行锁是通过给索引项加锁实现的,如果没有索引,InnoDB
会通过隐藏的聚簇索引来对记录加锁。也就是说:如果不通过索引条件检索数据,那么InnoDB将对表中所有数据加锁,实际效果跟表锁一样。因为没有了索引,找到某一条记录就得扫描全表,要扫描全表,就得锁定表。

至此问题解决

该次死锁产生的原因是:
1、两个事务对sql的调用是相反的,导致相互持有对方的锁
2、数据类型传递不规范导致索引失效从而引起表锁

附上常用解决死锁需要用到的sql命令:

SHOW ENGINE INNODB STATUS / /查看最近一次数据死锁的日志
SET @@autocommit=0; / /将事务设置为手动提交
SHOW VARIABLES LIKE ‘%autocommit%’ / /查看事务是否设置为手动提交

相关文章: