【发布时间】:2015-12-24 06:49:39
【问题描述】:
- MySQL 版本:5.6
- 存储引擎:InnoDB
当两个任务尝试select 然后insert 同一个表时发生死锁。过程如下:
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, ACTIVE 0 sec, process no 4690, OS thread id 140411389953792 inserting, thread declared inside InnoDB 500
mysql tables in use 1, locked 1
1172 lock struct(s), heap size 112624, 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 lock 在要插入的单行上。那为什么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 |
【问题讨论】:
-
您可以将事务的隔离级别更改为可序列化。但通常最好的做法是尽可能避免在事务中使用
selects。 -
这里有一些关于死锁的有趣信息:dev.mysql.com/doc/refman/5.7/en/innodb-deadlocks.html
-
交易来源是否相同?
-
@MuhammadMuazzam 不,这两个事务是由 IBATIS API 生成的两个不同会话调用的。
-
你能在同一个地方测试它吗?然后发生了什么?