gpt4 book ai didi

MySQL InnoDB 在 SELECT 上使用排他锁死锁(用于更新)

转载 作者:可可西里 更新时间:2023-11-01 06:45:18 25 4
gpt4 key购买 nike

我这样做是为了确保这个进程的实例只运行一次(伪代码 php/mysql innodb):

START TRANSACTION
$rpid = SELECT `value` FROM locks WHERE name = "lock_name" FOR UPDATE
$pid = posix_getpid();
if($rpid > 0){
$isRunning = posix_kill($rpid, 0);
if(!$isRunning){ // isRunning
INSERT INTO locks values('lock_name', $pid) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)
}else{
ROLLBACK
echo "Allready running...\n";
exit();
}
}else{ // if rpid == 0 -
INSERT INTO locks values('lock_name', $pid) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)
}
COMMIT

...............

//free the pid
INSERT INTO locks values('lock_name', 0) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)

表锁包含这些字段:

id - primary, autoinc
name - varchar(64) unique key
description - text
value - text

我相信从 START TRANSACTIN 到 COMMIT/ROLLBACK 的时间真的是几毫秒——没有足够的时间甚至超时。这段代码怎么可能陷入僵局?我不在此事务中使用其他表。看起来死锁是不可能的。如果 2 个进程同时启动,第一个获得该行锁的进程将继续,另一个将等待锁被释放。如果在 1 分钟内没有释放锁,则错误是“超时”,而不是死锁。

最佳答案

SELECT FOR UPDATE 在获取记录的独占锁之前获取表的意向独占锁。

因此,在这种情况下:

X1: SELECT FOR UPDATE -- holds IX, holds X on 'lock_name'
X2: SELECT FOR UPDATE -- holds IX, waits for X on 'lock_name'
X1: INSERT -- holds IX, waits for X for the gap on `id`

发生死锁,因为两个事务都持有表上的 IX 锁并等待记录上的 X 锁。

实际上,MySQL manual on locking 中描述了这种情况.

要解决这个问题,您需要删除除您正在搜索的索引之外的所有索引,即 lock_name

只需将主键放在 id 上。

关于MySQL InnoDB 在 SELECT 上使用排他锁死锁(用于更新),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5432370/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com