//
insert同一条数据引发的锁争用
//
今天做了个简单的死锁测试,当3个会话中同时进行同一条insert语句时,回滚其中一条,另外两条会发生死锁。
例如对于一个id作为主键的表table,当按照下列顺序执行insert操作的时候:
session 1
begin;
insert into table values (5); --- query ok;
session 2
begin ;
insert into table values (5); ---等待
session3
begin ;
insert into table values (5); ---等待
session 1
rollback;
session 2
insert into table values (5); --- query ok;
session 3
insert into table values (5);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
可以看到,当session 1 插入的时候,还没有rollback之前,session2 和session3都处于等待状态,而query 1 rollback之后,session2执行成功,session3 出现检测到死锁的报错。
说下这个死锁的成因:
1、session 1占有id=5记录上的排它锁
2、session2 和session 3 分别请求排他记录锁,但是因为记录存在冲突的现象,所以分别转换成共享记录锁
3、session 1 rollback之后,session2 和session 3都想获取id=5这一列的排他记录锁,但是都在等待对方释放共享记录锁,因此形成死锁。
4、mysql检测到死锁,根据内部机制,将session2 的执行成功,session 3的报告错误
这个中间有个疑点,为什么记录存在冲突的时候,会将所请求的排它锁转换为共享记录锁?这个问题还有待验证。大家可以模拟一下,中途使用:
select * from information_schema.innodb_locks;
来查看等待期间的锁类型。
使用show engine innodb status来查看锁的日志。