由并发INSERT和SELECT引起的MySQL死锁

> MySQL版本:5.6
>存储引擎:InnoDB

当两个任务尝试选择然后插入同一个表时发生死锁.程序如下:

Task_1       Task_2
          ------      ------
Phase 1 | SELECT      SELECT
Phase 2 | INSERT      INSERT

SELECT count(id) from mytbl where name = 'someValue' and timestampdiff(hour,ts,Now()) < 1;
INSERT mytbl (id,name,ts) values ('newId','anotherValue',Now());

死锁日志如下(一些细节被截断):

------------------------
LATEST DETECTED DEADLOCK
------------------------
151225  8:22:17
*** (1) TRANSACTION:
TRANSACTION 0 746402,ACTIVE 0 sec,process no 4690,OS thread id 140411390486272 inserting
MysqL tables in use 1,locked 1
LOCK WAIT 1172 lock struct(s),heap size 112624,32914 row lock(s)
MysqL thread id 3909,query id 31751474 10.20.36.38 mydb update
INSERT INTO mytbl -- truncated
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 5044 n bits 88 index `PRIMARY` of table `MYDB`.`mytbl` trx id 0 746402 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 0 746449,OS thread id 140411389953792 inserting,thread declared inside InnoDB 500
MysqL tables in use 1,locked 1
1172 lock struct(s),32914 row lock(s)
MysqL thread id 3906,query id 31751477 10.20.36.38 mydb update
INSERT INTO mytbl  -- truncated
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 5044 n bits 88 index `PRIMARY` of table `MYDB`.`MYTBL` trx id 0 746449 lock mode S
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 0 page no 5044 n bits 88 index `PRIMARY` of table `MYDB`.`MYTBL` trx id 0 746449 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)

问题

>根据MysqL手册,简单的SELECT语句使用不需要S锁定的快照读取. INSERT语句需要插入单行上的X锁.那么为什么Task_2持有S锁并导致僵局?

编辑

SHOW CREATE TABLE的结果如下:

| task_content | CREATE TABLE `mytbl` (
`id` bigint(20) NOT NULL,`ts` timestamp NULL DEFAULT NULL,`name` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

解决方法

如果您当前的隔离级别可重复读取或更强,则为了能够在事务中重复相同的结果(select count(id))… MysqL必须锁定整个主键(或者WHERE条件使用的另一个键的一部分) ).然后通过插入一个新值修改该键.但是并发事务会修改密钥的状态,这已经被看到了.两者都可以以相同的密钥状态开始,然后等待另一个完成,没有任何更改,这样它将应用自己的更改.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 &#39;EastRiver&#39; 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...