innodb next-key lock引发的死锁

innodb的事务隔离级别是可重复读级别且innodb_locks_unsafe_for_binlog禁用,也就是说允许next-key
lock

CREATE TABLE `LockTest` (
   `order_id` varchar(20) NOT NULL,
   `id` bigint(20) NOT NULL AUTO_INCREMENT,
   PRIMARY KEY (`id`),
   KEY `idx_order_id` (`order_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8




















事务1 事务2

begin

delete from LockTest where order_id =  ‘D20‘

 
 
begin

delete from LockTest where order_id =  ‘D19‘

insert into LockTest (order_id) values (‘D20‘)

 
 

insert into LockTest (order_id) values (‘D19‘)

commit

commit

事务1 执行到insert语句会block住,事务2执行insert语句会提示死锁错误

错误码: 1213
Deadlock found when trying to get lock; try restarting
transaction

Execution Time : 00:00:00:000
Transfer Time : 00:00:00:000
Total Time
: 00:00:00:000

show engine innodb status 显示死锁信息

------------------------
LATEST DETECTED
DEADLOCK
------------------------
2014-04-30 15:01:55 a233b90
*** (1)
TRANSACTION:
TRANSACTION 596042, ACTIVE 7 sec inserting
mysql tables in
use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 320, 2 row lock(s),
undo log entries 1
MySQL thread id 10851, OS thread handle 0x2abfb90, query
id 251521 10.10.53.122 root update
insert into LockTest (order_id) values
(‘D20‘)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id
502 page no 4 n bits 72 index `idx_order_id` of table `test`.`LockTest` trx id
596042 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL
RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex
73757072656d756d; asc supremum;;

*** (2) TRANSACTION:
TRANSACTION 596041, ACTIVE 19 sec inserting
mysql
tables in use 1, locked 1
3 lock struct(s), heap size 320, 2 row lock(s),
undo log entries 1
MySQL thread id 10848, OS thread handle 0xa233b90, query
id 251522 10.10.53.122 root update
insert into LockTest (order_id) values
(‘D19‘)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 502 page no 4 n
bits 72 index `idx_order_id` of table `test`.`LockTest` trx id 596041 lock_mode
X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info
bits 0
0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 502
page no 4 n bits 72 index `idx_order_id` of table `test`.`LockTest` trx id
596041 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL
RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex
73757072656d756d; asc supremum;;

*** WE ROLL BACK TRANSACTION (2)

简单分析上面的场景先删除再插入的sql是hibernage保存集合关联的处理方式。delete语句删除不存在且删除的order_id大于现有表中的所有order_id,所以delete语句会使用next-key锁住(当前最大-无穷大)


































lock_id lock_trx_id lock_mode lock_type lock_table lock_index lock_space lock_page lock_rec lock_data
596133:502:4:1 596133 X RECORD `test`.`LockTest` idx_order_id 502 4 1 supremum pseudo-record
596134:502:4:1 596134 X RECORD `test`.`LockTest` idx_order_id 502 4 1 supremum pseudo-record

比较奇怪的是为啥两个事务都拿到了相同区间的(当前最大-无穷大)的X锁。不过换成read-commited级别后就没死锁了。

终于在官方文档找到答案, 区间锁只是用来防止其他事务在区间中插入数据,区间x锁
与区间S锁效果是一样的。也就是说不会因为两个事务都用加相同区间锁而相互等待的

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

Gap locks in InnoDB are “purely inhibitive”, which
means they only stop other transactions from inserting to the gap. Thus, a gap
X-lock has the same effect as a gap S-lock.

当两个事务拿到相同区间锁后,就会阻止对方忘区间内做insert操作。所以第一个事务insert会阻塞,第二个事务会提示死锁

innodb next-key lock引发的死锁,码迷,mamicode.com

时间: 2024-08-02 06:59:58

innodb next-key lock引发的死锁的相关文章

关于InnoDB的Next-Key lock

最近一段时间在准备新员工培训的材料,本来打算介绍介绍概念就OK的,但是既然写了事务的章节,就特别想介绍一下锁,介绍了锁,就忍不住想介绍一下Next-Key Lock. 大家知道,标准的事务隔离级别有READ UNCOMMITTED,READ COMMITTED,REPEATED READ和SERIALIZABLE.其中InnoDB默认实现了REPEATED READ级别,这个级别可以解决非一致性读的问题,但是不能解决幻读的问题,不过InnoDB采用了Next Key Lock算法,在该级别实现了

Key lock 的秘密

研究死锁,或者观察sp_lock,有时候最恼人的莫过于你看到下面研究成果的key lock,但是却不知道究竟是哪个page 哪个row被lock住了: Exec sp_lock:   就说上面的key (9dd27be994c0) 吧,能不能知道这个key,究竟是对应于那个table,那个data page,甚至哪一行(row)呢? 可以的.且听我慢慢说来. 先说这一行: 52        20        978102525      2          KEY      (9dd27b

[ERROR] InnoDB: Unable to lock ./ibdata1, error: 11

问题描述:启动MySQL后,出现连接不上,报 [ERROR] InnoDB: Unable to lock ./ibdata1, error: 11[[email protected] ~]# service mysql startStarting MySQL [ OK ][[email protected] ~]# mysql -uroot -poracleWarning: Using a password on the command line interface can be insecu

更新一张没有主键的数据表,引发的死锁

不介绍背景,直接上例子 首先我们创建这样的一张表,没有主键,添加下面的数据 然后我们分别创建下面的连个连接查询 查询1: SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED--SERIALIZABLE--READ UNCOMMITTEDbegin tran print convert(nvarchar(30),convert(datetime,getdate(),121),121) update table1 set A='aa' where B='

innodb table level lock 与lock table语句关系

DDL语句只申请意向级别的表锁.在lock table语句中,mysql会申请mysql级别表锁,同时innodb也会申请innodb级别表锁.前提是innodb_table_locks=1 https://www.percona.com/blog/2012/07/31/innodb-table-locks/ MySQL Table level locks and Innodb Table Levellocks are two separate beings. You almost never

记录一次高并发下由索引引发的死锁问题

先上一个存储过程 CREATE PROCEDURE [dbo].[GetNextIncrease] @key varchar(50), @next int output as begin begin try begin tran select @next=NextVal from cfg_increase with(xlock,rowlock) where [Key]=@key; --if @next!=NULL begin update cfg_increase set NextVal=(Ne

一个查询语句引发的死锁

程序错误日志大量的报死锁错误,去数据库错误日志查看确实有很多死锁(应在数据库实例启动时执行dbcc traceon(1222,-1)开启死锁跟踪): 04/29/2016 14:07:51,spid33s,δ?,waiter id=process71da6bb88 mode=IX requestType=wait 04/29/2016 14:07:51,spid33s,δ?,waiter-list 04/29/2016 14:07:51,spid33s,δ?,owner id=process5b

从ext4将mysql数据目录移动至lustre出现(InnoDB: Unable to lock ./ibdata1, error: 38.)

因为数据目录过大,因此我把目录从本地移到了共享存储中.在修改了/etc/my.cnf和/etc/init.d/mysqld之后发现数据库可以运行,但启动速度很慢 原因是原文件系统是ext4,而目标文件系统是lustre.lustre默认没有enable lock功能.而Mysqld启动时需要lock ibdata1.于是一直在lock.因为我数据库中并没有innode engine的表.所以数据库可以启动. 解决方法: 1.如果像我一样不需要innode功能,那么在mysql配置文件(/etc/

mysql 中的 latch锁和Tlock(事务锁), DML加锁规则,以及死锁分析。

一.Latch和Tlock的关系 Latch:为保护临界资源的正确性而设计,例如保护正在使用的内存页面不被破坏等. 没有死锁检测机制,轻量锁,并且作用对象时内存页面或是内存共享变量. Tlock:事务锁,作用对象是事务,有死锁检测机制. 在innodb内部,为了减少死锁的发生概率,Latch不会等待Tlock. 线程获取行锁的流程: 在对行加锁的时候会先对行所在的页面添加lath,然后再对行添加Tlock,待对行添加完Tlock后再释放页面的Lath. 这种机制主要是为了保证线程获取的行数据的一