使用多线程代码在一张表上发生 MySQL 死锁
Posted
技术标签:
【中文标题】使用多线程代码在一张表上发生 MySQL 死锁【英文标题】:MySQL deadlock on one table with multithreading code 【发布时间】:2016-03-16 22:46:45 【问题描述】:我创建了一个收集价格并将其存储在数据库中的应用程序。 该应用程序使用两个线程运行。但时不时会出现死锁。我认为这是因为踏板将大量价格插入到同一张表中。
桌子
[tripid | date | duration | price | garant | updatetime | persons | accommodationid]
索引
unique (tripid, date, duration, price, persons)
foreign key 'accommodationid' to table 'accommodation.id'
查询
insert into prices (tripid, date, duration, price, persons, accomodationid)
values ( 1 , 2016-6-4, 8, 200,2,32),
... a whole lot more ...
( 1 , 2016-7-4, 8, 200,2,32)
on duplicate key update price = values(price);
因为可以在 1 个查询中插入 1000 个值,所以需要一些时间。我认为当第二个线程想要插入另外 1000 个值但第一个未完成时会发生死锁。
innodb 状态
------------------------
LATEST DETECTED DEADLOCK
------------------------
2016-03-16 23:13:13 0xef8
*** (1) TRANSACTION:
TRANSACTION 3732195928, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 415, OS thread handle 7328, query id 10956855 ---(ip)-- --name-- update
insert into `prices` (tripid,`date`,`duration`,`price`,`garant`,`updatetime`,`persons`,`accommodationid`) values
(179881,'2016-03-18',2,206,'0','2016-03-16','1','119'),(179881,'2016-03-18',3,260,'0','2016-03-16','1','119'),(179881,'2016-03-18',4,313,'0','2016-03-16','1','119'),(179881,'2016-03-18',5,366,'0','2016-03-16','1','119'),(179881,'2016-03-19',2,206,'0','2016-03-16','1','119'),(179881,'2016-03-19',3,260,'0','2016-03-16','1','119'),(179881,'2016-03-19',4,313,'0','2016-03-16','1','119'),(179881,'2016-03-19',5,366,'0','2016-03-16','1','119'),(179881,'2016-03-20',2,206,'0','2016-03-16','1','119'),(179881,'2016-03-20',3,260,'0','2016-03-16','1','119'),(179881,'2016-03-20',4,313,'0','2016-03-16','1','119'),(179881,'2016-03-20',5,366,'0','2016-03-16','1','119'),(179881,'2016-03-21',2,206,'0','2016-03-16','1','119'),(179881,'2016-03-21',3,260,'0','2016-03-16','1','119'),(179881,'2016-03-21',4,313,
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 247 page no 1457 n bits 136 index keyGroup of table `travel`.`prices` trx id 3732195928 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 3732195927, ACTIVE 0 sec inserting, thread declared inside InnoDB 4529
mysql tables in use 1, locked 1
15 lock struct(s), heap size 1136, 476 row lock(s), undo log entries 472
MySQL thread id 414, OS thread handle 3832, query id 10956852 ---(ip)-- --name-- update
insert into `prices` (tripid,`date`,`duration`,`price`,`garant`,`updatetime`,`persons`,`accommodationid`) values
(179880,'2016-03-18',2,185,'0','2016-03-16','1','1438'),(179880,'2016-03-18',3,217,'0','2016-03-16','1','1438'),(179880,'2016-03-18',4,249,'0','2016-03-16','1','1438'),(179880,'2016-03-18',5,279,'0','2016-03-16','1','1438'),(179880,'2016-03-18',6,312,'0','2016-03-16','1','1438'),(179880,'2016-03-18',7,343,'0','2016-03-16','1','1438'),(179880,'2016-03-18',8,375,'0','2016-03-16','1','1438'),(179880,'2016-03-19',2,185,'0','2016-03-16','1','1438'),(179880,'2016-03-19',3,217,'0','2016-03-16','1','1438'),(179880,'2016-03-19',4,249,'0','2016-03-16','1','1438'),(179880,'2016-03-19',5,279,'0','2016-03-16','1','1438'),(179880,'2016-03-19',6,312,'0','2016-03-16','1','1438'),(179880,'2016-03-19',7,343,'0','2016-03-16','1','1438'),(179880,'2016-03-20',2,185,'0','2016-03-16','1','1438'),(179880,'2016
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 247 page no 1457 n bits 72 index keyGroup of table `travel`.`prices` trx id 3732195927 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 247 page no 1457 n bits 136 index keyGroup of table `travel`.`prices` trx id 3732195927 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 (1)
------------
问题
如何避免死锁?
【问题讨论】:
通过使用单个线程,至少用于插入/更新。 该应用程序的功能更多。如果我在应用程序中使用更多线程,我可以将计算价格的整个过程缩短 4 小时。所以说“使用 1 个线程”是不是有点简单? 【参考方案1】:我似乎已经通过首先锁定表来修复它,然后执行大量查询并解锁它,以便第二个线程获得访问权限。
LOCK TABLES prices WRITE;
insert into prices (tripid, date, duration, price, persons, accomodationid)
values ( 1 , 2016-6-4, 8, 200,2,32),
... a whole lot more ...
( 1 , 2016-7-4, 8, 200,2,32)
on duplicate key update price = values(price);
UNLOCK TABLES;
【讨论】:
这有效地使应用程序成为单线程,因为在任何时候,最多一个线程处于活动状态,而其他线程在等待。 (车队锁) 嗯.. 这不会使应用程序成为单线程,只会执行此查询。该应用程序会执行大量其他操作,并且每 10 分钟一次,它们会同时执行此查询。所以如果等待另一个线程完成这个查询也没问题。以上是关于使用多线程代码在一张表上发生 MySQL 死锁的主要内容,如果未能解决你的问题,请参考以下文章