避免插入与选择相结合的 SQL 死锁

Posted

技术标签:

【中文标题】避免插入与选择相结合的 SQL 死锁【英文标题】:Avoiding SQL deadlock in insert combined with select 【发布时间】:2013-01-25 22:30:03 【问题描述】:

我正在尝试将页面插入到带有排序列的表中,我以这种方式自动递增 2000:

INSERT INTO pages (sort,img_url,thumb_url,name,img_height,plank_id)
SELECT IFNULL(max(sort),0)+2000,'/image/path.jpg','/image/path.jpg','name',1600,'3'
FROM pages WHERE plank_id = '3'

问题是我在上传图片时触发了这些插入,所以这些查询中有 5-10 个几乎同时运行。由于某种原因,这会触发某些文件的死锁。

知道发生了什么吗?

编辑:我正在运行 mysql 5.5.24 和 InnoDB。排序列有一个索引。

【问题讨论】:

出于某种原因?几乎可以肯定是因为选择最大值。 排序列有索引吗? 你用的是什么关系型数据库? sort 唯一的 - 可以将其设为自动增量列吗?为什么不存储图像的宽度和高度? @MartinSmith 我相信我正在运行 MySQL 5.5.24 【参考方案1】:

我为自己做的是在插入时将sort 设置为0,检索插入行的id 并将sort 设置为id*2000。但是,您也可以尝试使用事务:

BEGIN;
INSERT INTO pages (sort,img_url,thumb_url,name,img_height,plank_id)
SELECT IFNULL(max(sort),0)+2000,'/image/path.jpg','/image/path.jpg','name',1600,'3'
FROM pages WHERE plank_id = '3';
COMMIT;

请注意,并非所有 MySQL 客户端库都支持多查询,因此您可能必须单独执行它们,但要在一个连接的流中执行。

另一种方法是在执行INSERT 时锁定整个表,但这会导致查询队列增加,因为它们必须等到执行插入操作

【讨论】:

以上是关于避免插入与选择相结合的 SQL 死锁的主要内容,如果未能解决你的问题,请参考以下文章

如何避免这两个 SQL 语句之间出现死锁?

如何解决多线程造成的数据库死锁

避免 SQL 事务中的死锁

进程死锁与避免

mysql 开发进阶篇系列 14 锁问题(避免死锁,死锁查看分析)

避免与 Future 阻塞 发生死锁