`
san_yun
  • 浏览: 2663163 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

MYSQL INNODB中GAP LOCK引起死锁的问题

 
阅读更多

先了解一下什么是GAP LOCK

在INNODB中,record-level lock大致有三种:Record, Gap, and Next-KeyLocks。简单的说,RECORDLOCK就是锁住某一行记录;而GAPLOCK会锁住某一段范围中的记录;NEXT-KEYLOCK则是前两者加起来的效果。

下面是MYSQL官方文档中相关内容的链接

http://dev.mysql.com/doc/refman/5.1/en/innodb-record-level-locks.html

 

有资料里说MYSQL的GAP LOCK最初是为了避免Phantom (幻象读)的问题,关于幻象读这里就不多做解释了,可以参考如下链接

http://dev.mysql.com/doc/refman/5.1/en/innodb-next-key-locking.html

 

可是毕竟GAPLOCK导致了锁定范围的增大,在某些情况下可能会造成一些不符合预期的现象。下面是一个简单的测试例子,先对GAP LOCK有个感性的认识

mysql> desc ts_column_log_test

    -> ;

+------------+-------------+------+-----+---------------------+----------------+

| Field      |Type        | Null | Key |Default            | Extra          |

+------------+-------------+------+-----+---------------------+----------------+

|id         |int(11)     | NO   | PRI |NULL               | auto_increment |

| col_id     |int(11)     | NO   | MUL |NULL               |               |

| start_time | timestamp   |NO   |     | 0000-00-00 00:00:00|               |

| end_time   |timestamp   | NO   |     | 0000-00-0000:00:00|               |

| data_time  | timestamp   |NO   |     | 0000-00-00 00:00:00|               |

| status     |varchar(30) | NO   |     |NULL               |               |

+------------+-------------+------+-----+---------------------+----------------+

6 rows in set (0.01 sec)

 

mysql> select * from ts_column_log_test; 

+----+--------+---------------------+---------------------+---------------------+---------+

| id | col_id |start_time          |end_time            |data_time           |status  |

+----+--------+---------------------+---------------------+---------------------+---------+

|  1 |      2| 2011-12-13 11:51:11 | 2011-12-13 11:51:11 | 2011-12-09 00:00:00 | running |

|  2 |     20 |2011-12-13 11:51:16 | 2011-12-13 11:51:16 | 2011-12-09 00:00:00 | running |

|  3 |    120 |2011-12-13 11:51:20 | 2011-12-13 11:51:20 | 2011-12-09 00:00:00 | running |

+----+--------+---------------------+---------------------+---------------------+---------+

3 rows in set (0.00 sec)

 

开启两个不同的会话,分别执行一些语句观察一下结果:

session1

mysql> set autocommit=0;

mysql> delete from ts_column_log_testwhere col_id=10;

Query OK, 0 rows affected (0.00sec)        --此时[2,20)这个区间内的记录都已经被GAP LOCK锁住了,如果在其他事务中尝试插入这些值,则会等待

 

session2

mysql> set autocommit=0;

mysql> INSERT INTO ts_column_log_test(col_id, start_time, end_time, data_time, status) VALUES (1, NULL, NULL,'20111209', 'running');  --成功

...

mysql> INSERT INTO ts_column_log_test(col_id, start_time, end_time, data_time, status) VALUES (2, NULL, NULL,'20111209', 'running');  --等待

...

mysql> INSERT INTO ts_column_log_test(col_id, start_time, end_time, data_time, status) VALUES (19, NULL, NULL,'20111209', 'running');  --等待

...

 

上面的实验很简单,大家可以自己测一下。这里解释一下会产生这种现象的原因:session1中的delete语句中指定条件where col_id=10,这时MYSQL会去扫描索引,但是这个时候delete语句获取的不是一个RECORD LOCK,而是一个NEXT-KEY LOCK。以当前值(10)为例,会向左扫描至col_id=2这条记录,向右扫描至col_id=20这条记录,锁定区间为前闭后开,即[2,20)。

下面是摘自官方手册里的一句话:

DELETE FROM ... WHERE ... sets an exclusivenext-key lock on every record the search encounters.

下面的链接里面有INNODB中各种不同的语句可能持有哪些锁的解释

http://dev.mysql.com/doc/refman/5.1/en/innodb-locks-set.html

 

明白了GAPLOCK是怎么回事,下面看下可能产生的问题吧

有时候我们会多个进程或线程并行的对同一张表进行操作,并且使用了事务,那么就可能会有问题,举个例子:

session1:

delete from ts_column_log_test wherecol_id=10;

INSERT INTO ts_column_log_test (col_id,start_time, end_time, data_time, status) VALUES (10, NULL, NULL, '20111209','running');

 

session2:

delete from ts_column_log_test wherecol_id=11;

INSERT INTO ts_column_log_test (col_id,start_time, end_time, data_time, status) VALUES (11, NULL, NULL, '20111209','running');

 

假设上面是你程序的两个进程需要做的操作,在没有并发的情况下,可能运行正常,因为每个事务在MYSQL中最终都是串行执行,中间并没有其他事务同时进行;可并发高了以后,可能在MYSQL中实际运行的语句顺序就会变成下面这个样子:

tx_num  time            statement

111     2011-12-12 10:00:00 delete from ts_column_log_test wherecol_id=10;

222      2011-12-1210:00:00 delete from ts_column_log_test where col_id=11;

111     2011-12-12 10:00:00 INSERT INTO ts_column_log_test (col_id,start_time, end_time, data_time, status) VALUES (10, NULL, NULL, '20111209','running');

222      2011-12-1210:00:00 INSERT INTO ts_column_log_test (col_id, start_time, end_time,data_time, status) VALUES (11, NULL, NULL, '20111209', 'running');

 

这个时候,你可能就会得到错误提示ERROR 1213 (40001): Deadlock found when trying toget lock; try restarting transaction。

原因是前两条语句都已经获得了[2,20)这个区间内记录的S锁,然后两个事务又分别对该区间段内的col_id=10这个位置请求X锁,这时就发生死锁,谁都请求不到X锁,因为互相都持有S锁。

 

解决方案有两种

1、改变程序中数据库操作的逻辑

2、取消GAP LOCK机制

Gap locking can be disabled explicitly.This occurs if you change the transaction isolation level to READ COMMITTED orenable the innodb_locks_unsafe_for_binlog system variable.

分享到:
评论

相关推荐

    innodb GAP LOCK 死锁例子1

    InnoDB GAP LOCK 死锁例子1 InnoDB 的记录锁机制是 MySQL 中最为复杂和强大的锁机制之一。Gap Lock 是 InnoDB 中的一种锁机制,它的主要作用是避免幻读(Phantom)问题。 在 InnoDB 中,记录锁机制可以分为三种...

    何登成 - 管中窥豹——MySQL(InnoDB)死锁分析之道

    何登成在其演讲中深入探讨了MySQL(InnoDB)死锁问题,尤其对于死锁的分析提出了独到的见解和方法。以下是对何登成演讲内容的知识点详细梳理: ### 为什么选择“死锁” 何登成首先分享了他选择探讨死锁话题的原因,...

    mysql死锁分析

    对于MySQL/InnoDB数据库而言,了解死锁的产生机制、分析死锁的方法以及如何预防死锁是非常重要的。 #### 一个不可思议的死锁 假设有一个表`dltask`,其结构如下: ```sql CREATE TABLE dltask ( id bigint ...

    mysql死锁的一些案例

    在MySQL中,InnoDB存储引擎通过死锁检测机制来解决这个问题。当检测到死锁时,会回滚其中一个事务,让另一个事务继续执行,以打破循环等待。这个过程可以通过`innodb_lock_wait_timeout`配置参数来控制超时时间。 ...

    innodb插件mysql

    2. **锁机制**:InnoDB Plugin提供了更细粒度的锁控制,如gap lock和next-key lock,以减少死锁的可能性,并优化并发性能。 3. **自适应哈希索引**:动态调整哈希索引的构建,根据查询模式自动创建和调整,进一步...

    一次MYSQL死锁分析案例1

    在MySQL数据库中,死锁是一种常见的并发问题,当两个或多个事务互相等待对方释放资源时,就会发生死锁。本案例中的死锁发生在“pop购药”系统的订单支付状态更新操作中,涉及到了两个事务,我们分别称之为Session1和...

    MySQL中InnoDB的间隙锁问题

    综上所述,理解InnoDB的间隙锁以及其带来的死锁问题对于优化MySQL数据库性能至关重要。合理规划事务执行逻辑、选择合适的隔离级别、监控锁争用情况是解决死锁问题、提高数据库性能的有效措施。在实际应用中,应该...

    innodb锁

    **innodb锁**是MySQL数据库InnoDB存储引擎中的一种关键机制,用于管理并发事务并确保数据的一致性和完整性。在多用户环境下,InnoDB通过锁来实现事务的隔离,防止脏读、不可重复读和幻读等并发问题。这篇博客文章...

    mysql之innodb的锁分类介绍

    MySQL的InnoDB存储引擎在处理并发事务时,采用了多种锁机制来确保数据的一致性和安全性。本文主要介绍InnoDB的三种行锁分类:记录锁、区间锁和Next-Key锁。 1. 记录锁(Record Lock):这是最基本的锁类型,只锁定...

    MySQL的InnoDB中的各种锁是怎么工作的

    MySQL的InnoDB存储引擎在处理并发事务时,采用了多种锁机制来确保数据的一致性和并发性能。这些锁主要分为行级锁和表级锁。行级锁是InnoDB的默认锁策略,它允许更高的并发性,因为它只锁定操作的具体行,而不是整个...

    阿里大牛何sir 深入MySQL加锁处理分析

    - 对于可重复读(RR)隔离级别,InnoDB使用一种称为“next-key lock”的锁定方式,它是一种结合了记录锁(Record Lock)和间隙锁(Gap Lock)的锁,用于防止幻读。 复杂的SQL语句,尤其是涉及多个表的JOIN操作,其...

    MySQL中InnoDB存储引擎的锁的基本使用教程

    MySQL中的InnoDB存储引擎在处理并发事务时采用了行级锁(row-level locking)机制,这是它相较于其他如MyISAM(表级锁)和MEMORY(表级锁或页面锁)的一大优势,因为它提供了更高的并发性能。行级锁分为共享锁(S ...

    初学者从源码理解MySQL死锁问题

    MySQL数据库中的死锁是数据库操作中常见的问题,尤其对于初学者来说,理解并解决这个问题可能会带来困扰。本文将从源码角度深入解析MySQL死锁的产生机制,帮助读者更好地理解和应对这类问题。 首先,了解死锁的基本...

    mysql锁解决并发问题共7页.pdf.zip

    8. **间隙锁(Gap Locks)**:InnoDB存储引擎的一种特性,防止其他事务在已锁定的行之间的间隙插入新行,防止幻读现象。 9. **Next-Key Locks**:是InnoDB存储引擎中的行锁与间隙锁的组合,锁定指定行以及行之间的...

    MySQL学习笔记——叶志镔.pdf

    InnoDB中使用的完整行锁由三个部分组成:记录锁(Record Lock)、间隙锁(Gap Lock)以及Next-Key Lock。其中Next-Key Lock是一种组合了记录锁和间隙锁的锁机制,主要用于解决幻读问题。 #### 实践思考:SQL语句...

    最热门的MySQL 面试题汇总

    22. **MySQL中的锁**:主要包括行锁(如Record Lock、Gap Lock、Next-Key Lock)、表锁、页锁等。 23. **四种隔离级别**:Read Uncommitted(读未提交)、Read Committed(读已提交)、Repeatable Read(可重复读)...

Global site tag (gtag.js) - Google Analytics