php - 同时添加和更新记录时发生死锁错误

标签 php mysql deadlock

我们目前正在开发一个有很多交易的项目。用户在队列表中添加订单,另一个脚本处理事务。当添加事务和队列引擎同时工作时,会出现死锁错误。

队列表

CREATE TABLE `order_queue` (
    `OrderId` BIGINT(20) UNSIGNED NOT NULL,
    `State` TINYINT(3) UNSIGNED NOT NULL COMMENT '1=adding, 11=proccessing, 2=complete',
    `EngineId` SMALLINT(5) UNSIGNED NOT NULL,
    `AddTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`OrderId`),
    INDEX `State` (`State`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

添加交易

$db->beginTransaction();
$db->exec("INSERT INTO order_queue (OrderId, State, EngineId) VALUES ({$OrderId}, 1, 0)");
$db->commit();

最后我们有三个队列引擎来获取事务并发送另一个系统

$db->query("UPDATE order_queue SET State=11,EngineId={$EngineId} WHERE State=1 LIMIT 1");

$qOrder = $db->query("SELECT * FROM order_queue 
            WHERE State=11 AND EngineId={$EngineId}")->fetch();

echo $qOrder->OrderId;
//send the order to other systems
$db->exec("UPDATE order_queue SET State=2 WHERE OrderId={$qOrder->OrderId}");

如果此脚本同时运行,则会出现最常见的错误

SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction

我尝试了一些方法,首先检查 AddTime,然后在 $db->commit(); 行之后更改 State 等,但是问题没有解决。

如果你是我,你会怎么做?哪种方法最好?

最佳答案

您可以尝试使用“锁定共享模式”,如下所示

$db->query("UPDATE order_queue SET State=11,EngineId={$EngineId} WHERE State=1 LIMIT 1");

$qOrder = $db->query("SELECT * FROM order_queue 
            WHERE State=11 AND EngineId={$EngineId} lock in share mode")->fetch();

echo $qOrder->OrderId;
//send the order to other systems
$db->exec("UPDATE order_queue SET State=2 WHERE OrderId={$qOrder->OrderId}");

关于php - 同时添加和更新记录时发生死锁错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50169087/

相关文章:

concurrency - 测试 go channel 吞吐量 - 所有 goroutines 死锁

java - 为什么死锁没有发生?

javascript - Angular - 将 HTTP 发布数据发送到服务器 [HOW TO]

php - Zend Framework 1 更新操作

php - 导入CSV数据到MYSQL

mysql - 如何从表中获取所有外键类型中存在字段值的行

mysql - 为什么paxos在mysql group replication中跳转prepare阶段?

java - "Found 1 deadlock"但跟踪显示未被任何线程锁定

php - 我想按 1 2 3 4 1 2 3 4 的顺序对我的 CatId 进行排序,但有一个问题,如果 catid 相同,它首先检查 allocationId 最后 14 位数字

php - 是否可以使用在 URL 中传递的值来查询数据库,并使用 mod_rewrite 将查询结果写入 URL?