锁定行以进行两次更新

时间:2012-04-08 03:44:35

标签: php mysql sql innodb

我需要对行进行两次更新,但我需要确保它们一起完成,并且其他用户的其他查询都不会干扰它们。我知道SELECT...FOR UPDATE但我想在第一次更新后它当然会被解锁,这意味着有人可能会干扰第二次更新。如果其他人首先更新该行,则更新将起作用但会弄乱数据。反正是否确保两个更新发生了它们应该如何发生?我被告知有关交易,但据我所知,它们只对确保两个更新实际发生而不是它们是否“一起”发生有好处,除非我错了并且行将被锁定直到交易被提交? / p>

以下是查询:

SELECT z FROM table WHERE id='$id'

UPDATE table SET x=x+2 WHERE x>z

UPDATE table SET y=y+2 WHERE y>z

我犯了一个错误,并没有提供完整的信息。那是我的错。我已经更新了查询。我的问题是z也可以更新。如果在SELECT之后但在其他两次更新之前更新z,则数据可能会混乱。做交易BEGIN / COMMIT是否适用于此?

3 个答案:

答案 0 :(得分:0)

了解TRANSACTION http://dev.mysql.com/doc/refman/5.0/en/commit.html

[... connect ...]

mysql_query("BEGIN");

$query1 = mysql_query('UPDATE table SET x=x+2 WHERE x>y');
$query2 = mysql_query('UPDATE table SET y=y+2 WHERE y>y');

if($query1 && $query2) {
    mysql_query("COMMIT");  
    echo 'Save Done. All UPDATES done.';  
} else {
    mysql_query("ROLLBACK");  
    echo 'Error Save. All UPDATES reverted, and not done.';  
}

答案 1 :(得分:0)

有各种级别的交易,但基本上按照ACID属性,您应该期望在给定的交易中,所有读取和更新都执行始终,这意味着它将保留在有效状态,但更重要的是,事务是隔离,因为在另一个事务(线程)中完成的工作不会干扰您的事务(您的选择和更新SQL语句的分组):这允许您我们假设您是系统中唯一的执行线程,允许您提交该组工作(原子)或将其所有回滚。

每个数据库可能以不同的方式处理语义(有些可能会锁定行或列,有些可能会重新排序,有些可能会序列化)但这就是声明性数据库接口的优点:您担心要完成的工作。 / p>

如上所述,MySQL InnoDB是事务性的并且将支持上面提到的内容,因此确保您的表使用InnoDB进行组织,其他非事务引擎(例如MyISAM)不是事务性的,因此会强制您管理这些事务语义(手动锁定。

答案 2 :(得分:0)

一种方法是锁定整个表格:

LOCK TABLE `table` WRITE;
SELECT z FROM `table` WHERE id='$id';
UPDATE `table` SET x=x+2 WHERE x>z;
UPDATE `table` SET y=y+2 WHERE y>z;
UNLOCK TABLES;

这将阻止其他会话在SELECT和UPDATE期间从table表中写入和读取。

这是否是一个合适的解决方案取决于会话等待从表中读取或写入的适当程度。