Nic*_*oft 6 mysql deadlock innodb transactions
我这样做是为了确保只运行一次这个进程的实例(伪代码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`)
Run Code Online (Sandbox Code Playgroud)
表锁包含以下字段:
id - primary, autoinc
name - varchar(64) unique key
description - text
value - text
Run Code Online (Sandbox Code Playgroud)
我相信从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`
Run Code Online (Sandbox Code Playgroud)
发生死锁,因为两个事务都IX在对表进行X锁定并等待对记录的锁定.
实际上,这种情况MySQL在锁定手册中有所描述.
要解决这个问题,你需要除掉你正在搜索的索引之外的所有索引lock_name.
只需放下主键即可id.
多亏了Quassnoi的回答才弄清楚......
我可以:
$myPid = posix_getpid();
$gotIt = false;
while(true){
START TRANSACTION;
$pid = SELECT ... FOR UPDATE; // read pid and get lock on it
if(mysql_num_rows($result) == 0){
ROLLBACK;// release lock to avoid deadlock
INSERT IGNORE INTO locks VALUES('lockname', $myPid);
}else{
//pid existed, no insert is needed
break;
}
}
if($pid != $myPid){ //we did not insert that
if($pid>0 && isRunning($pid)){
ROLLBACK;
echo 'another process is running';
exit;
}{
// no other process is running - write $myPid in db
UPDATE locks SET value = $myPid WHERE name = 'lockname'; // update is safe
COMMIT;
}
}else{
ROLLBACK; // release lock
}
Run Code Online (Sandbox Code Playgroud)