`

mysql 2个sql更新不同记录但死锁

 
阅读更多

问题起因:

两条写sql,操作的记录没有任何冲突,但发生死锁

 

预备知识:

InnoDB行锁是通过给索引上的索引项加锁来实现的

 

创建测试表

CREATE TABLE `t1` (

  `pk_id` INT(11) NOT NULL,

  `type` INT(11) NOT NULL,

  `status` INT(11) NOT NULL,

  PRIMARY KEY (`pk_id`)

);

create index idx_type on t1(type);

create index idx_status on t1(status);

生成测试数据

INSERT INTO  t1 (pk_id,TYPE,STATUS)

VALUES

(1,1,0),

(2,1,0),

(3,1,0),

(4,2,0),

(5,2,0),

(6,1,1),

(7,1,1),

(8,2,1);

 

例1.不一样的锁等待

连接A执行

SET autocommit=0;

BEGIN;

SELECT * FROM t1 force index(PRIMARY) WHERE pk_id<4 AND TYPE=1 AND pk_id!=2 FOR UPDATE;

马上返回查到的结果有两条pk_id为1和3

 

连接B执行

SET autocommit=0;

BEGIN;

SELECT * FROM t1 WHERE pk_id=2 FOR UPDATE;

执行后连接B一直是等待状态,如果连接A commit,连接B马上就执行完成

说明:连接A虽然查出来的结果只有pk_id为1和3的两条记录,但把pk_id为2的PRIMARY索引记录也锁住了,所以连接B一直等待

 

换个索引试试

在连接A里

commit;

SELECT * FROM t1 force index(idx_type) WHERE pk_id<4 AND TYPE=1 AND pk_id!=2 FOR UPDATE;

注意只换了force index使用的索引,其他都没变

在连接B里想写操作TYPE=1的记录(pk_id为1、2、3、6、7)都等待,因为连接A把idx_type中TYPE=1的记录都锁了

和之前例子对照可以发现,索引锁是按使用的索引来操作,并且可以确定的是锁的范围会超出查询结果范围,这点和一般以为的不一样,具体算法还有待研究。

 

2.死锁

连接A执行

COMMIT;
SET autocommit=0;
SELECT * FROM t1 WHERE pk_id<5 FOR UPDATE;

连接A先锁住了pk索引的部分记录

 

接着连接B执行

COMMIT;
SET autocommit=0;

SELECT * FROM t1 FORCE INDEX (idx_status) WHERE STATUS=0 FOR UPDATE;

连接B锁往了idx_status的部分记录,再要锁pk时被连接A block,所以只能等待

 

最后连接A执行

UPDATE t1 SET STATUS=6 WHERE pk_id<5;

这时连接B报dead lock found

简单来讲连接A先锁住pk,B先锁住idx_status再拿pk就拿不到,这时A再拿idx_status就死锁了

类似于一个人有X但要Y,一个人有Y但要X,互不相让,就死锁了。

 

3.想不到的死锁

把例1和例2的情况结合起来,就会出来本文最开始碰到的问题,想不到的死锁,即更新的记录完全不冲突,但就是死锁了

比如

SELECT * FROM t1 force index(idx_type) WHERE pk_id<4 AND TYPE=1 FOR UPDATE;

update t1 set status=1 where pk_id=6

虽然想操作的记录不同,但锁的记录有相同的,所以也可能会死锁

 

例4.index merge死锁

如果sql where里同时使用了type和status,因为type和status上都有单字段索引,所以explain会发现使用了index merge

有的sql使用的索引是先idx_type再idx_status,有的先idx_status再idx_type

这样如果锁的记录有冲突,就可能和例3一样死锁了

 

解决方案:

1.只有一个pk,不要其他索引。这样只有lock wait,不会死锁

2.有多个index,但写数据时使用的都是同样的index组合

3.有多个index,按不同的index组合写数据,但逻辑上保证锁的记录不冲突

 

时间所限,只整理了大概的逻辑,一些细节未深入。有兴趣的可以看看mysql的next-key locking

0
2
分享到:
评论

相关推荐

    mysql死锁的一些案例

    这个SQL命令用于快速从文件中导入大量数据到MySQL表中。异常可能由以下原因引起: - 文件路径不正确或文件不存在。 - 文件格式不匹配,如字段分隔符、转义字符设置不正确。 - 权限问题:用户可能没有足够的权限...

    一个最不可思议的MySQL死锁分析1

    虽然这可能是导致死锁的一个因素,但从理论上来讲,删除相同记录的事务不应该发生死锁。然而,实际发生的死锁表明,我们必须更深入地理解InnoDB的锁机制和事务处理。 接下来,我们要学习如何解读MySQL的死锁日志。...

    mysql死锁解决

    在MySQL中,尤其是在InnoDB存储引擎下,当检测到死锁时,MySQL会自动选择回滚其中一个事务来解除死锁状态。 #### 二、死锁产生的原因 1. **循环等待**:多个事务之间存在循环的资源等待关系。 2. **互斥条件**:...

    mysql死锁分析

    在MySQL的使用过程中,死锁是一个较为常见的现象,尤其是在并发量较大的应用场景下。死锁的发生往往会给系统带来不可预知的影响,严重时甚至会导致整个数据库服务不可用。对于MySQL/InnoDB数据库而言,了解死锁的...

    MYSQL 数据库死锁

    MySQL数据库死锁是数据库系统中常见的问题,它发生在两个或多个事务在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力干涉它们将无法继续执行。了解和处理死锁是数据库管理员和开发人员必备的技能。...

    MySQL数据库CPU飙升及烂sql记录

    通过以上分析,我们可以看到,"MySQL数据库CPU飙升及烂sql记录"是一个多方面的问题,需要从多个角度进行诊断和处理。在实际操作中,我们需要结合具体环境,运用适当的工具和技术,确保数据库的稳定高效运行。对于...

    MySQL开发者SQL权威指南

    MySQL开发者SQL权威指南是一本专为MySQL开发人员设计的详细教程,旨在帮助读者深入理解和熟练掌握SQL语言在MySQL环境中的应用。SQL(Structured Query Language),结构化查询语言,是管理和处理关系数据库的标准...

    查看数据库死锁SQL

    根据提供的SQL脚本内容,我们可以看出该脚本主要用于查询MySQL数据库中出现死锁的情况,并获取相关信息,包括但不限于死锁的ID、导致死锁的具体SQL语句以及引发死锁的客户端等。通过这些信息,数据库管理员或开发...

    SQL死锁监控工具

    MySQL数据库虽然没有内置的死锁日志,但在InnoDB存储引擎中,当发生死锁时,会自动检测并回滚其中一个事务,同时记录在"SHOW ENGINE INNODB STATUS"的输出中。通过对这些信息的分析,可以了解死锁的详细过程。 除了...

    几种不常见的MySQL InnoDB 死锁情况--1

    2. 使用死锁检测机制,当检测到死锁时,MySQL会回滚其中一个事务以打破死锁循环。 3. 优化SQL查询,避免全表扫描,减少间隙锁的使用。 4. 考虑使用更宽松的事务隔离级别,如可重复读(Repeatable Read)降级为读已...

    大牛出手MySQL死锁深入分析

    本文将以一个具体的死锁案例为背景,深入分析MySQL中的死锁机制,探讨死锁的成因,并提出预防策略,旨在帮助读者清晰理解死锁问题的背景、阅读死锁日志的方法、深入剖析死锁的原因以及总结死锁问题。 首先,死锁...

    SQLMonitor2.4.3.6(监控Oracle和MYSQL语句)

    《SQLMonitor2.4.3.6:高效监控Oracle与MYSQL数据库操作的得力助手》 在数据库管理领域,实时监控数据库的运行状态和SQL语句执行情况是至关重要的任务,这有助于确保系统的稳定性和性能优化。SQLMonitor2.4.3.6是一...

    一次MYSQL死锁分析案例1

    本案例中的死锁发生在“pop购药”系统的订单支付状态更新操作中,涉及到了两个事务,我们分别称之为Session1和Session2。 首先,让我们详细解析一下这两个事务的操作: **Transaction 1 (Session1)**: 执行的SQL...

    MySQL 死锁产生原因和解决办法

    - **Session2**:尝试插入id为23的新记录,但由于Session1已经锁定了id为22的行,所以Session2在尝试插入id为23的记录时触发了死锁。 #### 三、解决死锁的方法 针对MySQL中的死锁问题,可以采取以下几种策略来预防...

    SQL2008中SQL应用之- 死锁(Deadlocking)

    两个并发的事务分别尝试更新`Purchasing.Vendor`表中的不同行,但顺序相反,从而导致死锁。当死锁发生时,SQL Server将返回错误消息`1205`,指示事务已被选为死锁牺牲品,需要重新运行。 为了预防和减少死锁,可以...

    该如何解决MySQL中的死锁问题.txt

    MySQL中的死锁是指两个或多个事务在相互等待对方释放资源,导致它们都无法继续执行的情况。解决MySQL中的死锁问题通常涉及多个方面,包括监控死锁、分析死锁原因、优化事务设计以及调整系统配置等。以下是一些解决...

    收集一些常见的 MySQL 死锁案例

    这个项目收集了一些常见的 MySQL 死锁案例,大多数案例都来源于网络,并对其进行分类汇总,试图通过死锁日志分析出每种死锁的原因,还原出死锁现场。 实际上,我们在定位死锁问题时,不仅应该对死锁日志进行分析,...

    Effective MySQL之SQL语句最优化

    "Effective MySQL之SQL语句最优化"这本书深入探讨了如何通过优化SQL查询来提高MySQL数据库的效率。以下是基于这个主题的一些关键知识点: 1. **索引优化**:索引是数据库性能提升的核心。书中的内容可能涵盖如何...

Global site tag (gtag.js) - Google Analytics