如果我有一个 InnoDB 表的简单语句
UPDATE <table> SET locked=1, col2=<Val2> WHERE locked=0
是否真的需要执行 SELECT FOR UPDATE?
由于 InnoDB 支持行级锁定,即使成千上万的客户端同时执行相同的脚本,是否有可能发生冲突?
更新:
像这样可以防止锁
$dbh = new PDO(DSN, DB_USER, DB_PASS);
$dbh->beginTransaction();
$selQuery = $dbh->prepare("SELECT <col> FROM <table> WHERE status=0 LIMIT 1 FOR UPDATE");
$selQuery->bindColumn(<col1>, $col1);
$selQuery->execute();
$selQuery->fetch(PDO::FETCH_BOUND);
$dbh->query("UPDATE <table> SET status=1 WHERE status=0 LIMIT 1");
$dbh->commit();
最佳答案
是的,碰撞总是会发生。所以使用设计模式:
SELECT FOR UPDATE
首先为给定事务中的所有资源,可以防止或缩短死锁情况。
假设以下场景:
- 进程 A 按 1,2 的顺序更新表 1 和 2
- 进程 B 按照 2,1 的顺序更新表 1 和 2
现在进程 A 更新表 1,同时进程 B 更新表 2,导致死锁(假设此更新命中了相同的“记录/页面”)。
但是,如果在事务开始时使用 SELECT FOR UPDATE
,事务将在开始时阻塞,因为表 2(或表 1,无论哪个更快)无法锁定(还) .这里的关键部分是“在交易开始时”,如果您稍后再做,那么只需运行 UPDATE
就同样有效。
关键始终是保持事务的原子性和快速性:对 SQL 逻辑进行分组,以便它可以使用最少数量的其他代码执行,并尽可能缩短锁定时间。
关于mysql - InnoDB 选择更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43530086/