先了解一下什么是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 的记录锁机制是 MySQL 中最为复杂和强大的锁机制之一。Gap Lock 是 InnoDB 中的一种锁机制,它的主要作用是避免幻读(Phantom)问题。 在 InnoDB 中,记录锁机制可以分为三种...
何登成在其演讲中深入探讨了MySQL(InnoDB)死锁问题,尤其对于死锁的分析提出了独到的见解和方法。以下是对何登成演讲内容的知识点详细梳理: ### 为什么选择“死锁” 何登成首先分享了他选择探讨死锁话题的原因,...
对于MySQL/InnoDB数据库而言,了解死锁的产生机制、分析死锁的方法以及如何预防死锁是非常重要的。 #### 一个不可思议的死锁 假设有一个表`dltask`,其结构如下: ```sql CREATE TABLE dltask ( id bigint ...
在MySQL中,InnoDB存储引擎通过死锁检测机制来解决这个问题。当检测到死锁时,会回滚其中一个事务,让另一个事务继续执行,以打破循环等待。这个过程可以通过`innodb_lock_wait_timeout`配置参数来控制超时时间。 ...
2. **锁机制**:InnoDB Plugin提供了更细粒度的锁控制,如gap lock和next-key lock,以减少死锁的可能性,并优化并发性能。 3. **自适应哈希索引**:动态调整哈希索引的构建,根据查询模式自动创建和调整,进一步...
在MySQL数据库中,死锁是一种常见的并发问题,当两个或多个事务互相等待对方释放资源时,就会发生死锁。本案例中的死锁发生在“pop购药”系统的订单支付状态更新操作中,涉及到了两个事务,我们分别称之为Session1和...
综上所述,理解InnoDB的间隙锁以及其带来的死锁问题对于优化MySQL数据库性能至关重要。合理规划事务执行逻辑、选择合适的隔离级别、监控锁争用情况是解决死锁问题、提高数据库性能的有效措施。在实际应用中,应该...
**innodb锁**是MySQL数据库InnoDB存储引擎中的一种关键机制,用于管理并发事务并确保数据的一致性和完整性。在多用户环境下,InnoDB通过锁来实现事务的隔离,防止脏读、不可重复读和幻读等并发问题。这篇博客文章...
MySQL的InnoDB存储引擎在处理并发事务时,采用了多种锁机制来确保数据的一致性和安全性。本文主要介绍InnoDB的三种行锁分类:记录锁、区间锁和Next-Key锁。 1. 记录锁(Record Lock):这是最基本的锁类型,只锁定...
MySQL的InnoDB存储引擎在处理并发事务时,采用了多种锁机制来确保数据的一致性和并发性能。这些锁主要分为行级锁和表级锁。行级锁是InnoDB的默认锁策略,它允许更高的并发性,因为它只锁定操作的具体行,而不是整个...
- 对于可重复读(RR)隔离级别,InnoDB使用一种称为“next-key lock”的锁定方式,它是一种结合了记录锁(Record Lock)和间隙锁(Gap Lock)的锁,用于防止幻读。 复杂的SQL语句,尤其是涉及多个表的JOIN操作,其...
MySQL中的InnoDB存储引擎在处理并发事务时采用了行级锁(row-level locking)机制,这是它相较于其他如MyISAM(表级锁)和MEMORY(表级锁或页面锁)的一大优势,因为它提供了更高的并发性能。行级锁分为共享锁(S ...
MySQL数据库中的死锁是数据库操作中常见的问题,尤其对于初学者来说,理解并解决这个问题可能会带来困扰。本文将从源码角度深入解析MySQL死锁的产生机制,帮助读者更好地理解和应对这类问题。 首先,了解死锁的基本...
8. **间隙锁(Gap Locks)**:InnoDB存储引擎的一种特性,防止其他事务在已锁定的行之间的间隙插入新行,防止幻读现象。 9. **Next-Key Locks**:是InnoDB存储引擎中的行锁与间隙锁的组合,锁定指定行以及行之间的...
InnoDB中使用的完整行锁由三个部分组成:记录锁(Record Lock)、间隙锁(Gap Lock)以及Next-Key Lock。其中Next-Key Lock是一种组合了记录锁和间隙锁的锁机制,主要用于解决幻读问题。 #### 实践思考:SQL语句...
22. **MySQL中的锁**:主要包括行锁(如Record Lock、Gap Lock、Next-Key Lock)、表锁、页锁等。 23. **四种隔离级别**:Read Uncommitted(读未提交)、Read Committed(读已提交)、Repeatable Read(可重复读)...