Php 锁定行以进行两次更新

Php 锁定行以进行两次更新,php,mysql,sql,innodb,Php,Mysql,Sql,Innodb,我需要对行进行两次更新,但我需要确保它们一起完成,并且其他用户的任何查询都不会干扰它们。我知道SELECT…FOR UPDATE,但我想在第一次更新之后,它当然会被解锁,这意味着有人可能会干扰第二次更新。如果其他人先更新该行,则更新将起作用,但会弄乱数据。是否有任何方法来确保这两个更新按预期方式进行?我被告知有事务,但据我所知,它们只适用于确保两个更新实际发生,而不是它们是否“一起”发生,除非我弄错了,并且在提交事务之前,行将被锁定 以下是查询: 从id='$id'的表中选择z 更新表格集x=x

我需要对行进行两次更新,但我需要确保它们一起完成,并且其他用户的任何查询都不会干扰它们。我知道
SELECT…FOR UPDATE
,但我想在第一次更新之后,它当然会被解锁,这意味着有人可能会干扰第二次更新。如果其他人先更新该行,则更新将起作用,但会弄乱数据。是否有任何方法来确保这两个更新按预期方式进行?我被告知有事务,但据我所知,它们只适用于确保两个更新实际发生,而不是它们是否“一起”发生,除非我弄错了,并且在提交事务之前,行将被锁定

以下是查询:

从id='$id'的表中选择z

更新表格集x=x+2,其中x>z

更新表格集y=y+2,其中y>z


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

了解交易


有各种级别的事务,但基本上根据属性,您应该期望在给定的事务中,所有读取和更新都一致地执行,这意味着它将保持在有效状态,但更重要的是,在另一个事务中执行的工作中,事务是隔离的(线程)不会干扰您的事务(您的select&update SQL语句分组):这允许您大致假设您是系统中唯一允许您以原子方式提交该工作组()或回滚该工作组的执行线程

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


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

一种方法是锁定整个表:

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;
这将防止其他会话在选择和更新期间从
表写入和读取


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

请参阅mysql TRANSACTIONS(),并与PHP(或任何语言)配合使用MySQL。@ GabrielSantos我提到了事务。在事务中间锁定的任何东西都会被锁定直到提交?QIGH,如果某些数据未被更新,你会回滚并给用户发送警告。如我在帖子中提到的,请参阅@ GabrielSantos,数据仍然能够更新,它可能只是错误地更新。你需要得到一个更新的数据吗?如果是的话,只需使用一个子查询。否则,你可以考虑使用“代码>开始事务,并有一致的快照;< /Cord>语句。我犯了一个错误,没有提供完整的信息。这是我的错。我已经更新了查询。我的问题是
z
也可以更新。如果
z
在选择之后更新,但在其他两次更新之前更新,数据可能会混乱。执行事务
BEGIN/COMMIT
是否可以做到这一点?将所有的insi只执行一个事务,如果任何条件失败,所有数据都将使用一个
回滚
if($query1&&$query2&&&$query3){COMMIT}或{ROLLBACK}还原
但是查询不一定会失败,如果我想得对的话,它们可能只会插入坏数据?这意味着它不会回滚,因为就它成功而言。这可能是因为我不清楚事务是如何工作的,这就是我感到困惑的原因。所有
更新
插入
或etc在执行最后一次查询之前不会被存储:
mysql\u查询(“提交”)
我无法帮助您使用innodb行锁,因为我对这个主题没有掌握。但是,您可以在这里询问:dba.stackexchange.com,并在特别介绍中看到这一点:dba.stackexchange.com/questions/15854/innodb-row-locking-how-to-implementation按事务和我上面的查询进行操作,如果用户在更新了
z
的事务中结束,是否有可能另一个事务中的某个人由于时间原因选择了
z
的旧值,然后在另一个用户已经更新了
z
的情况下,以旧的
z
值的名义执行其他查询?复杂的是,另一个事务#2可能会看到旧的v当事务#1在较低的隔离级别下进行处理时,z的值。在这种情况下,您需要验证可序列化的隔离。读得好:如果用户在保存锁定的表单之前关闭浏览器,表将保持锁定。@GabrielSantos您有参考来解释吗?我怀疑PHP脚本将继续运行,并且unl锁定表,否则脚本将中止,断开与数据库的连接,锁将被释放。Michal,您的示例是安全的,但是,如果我去编辑新闻id 5,例如,我说:MYSQL,锁定id为5的新闻,仅在保存时解锁。如果我不保存,行继续锁定(就像Joomla网站,每次我关闭页面而不保存时,我都需要解锁锁定的行)。Gabriel首先要澄清的是,我没有锁定答案中的任何特定行,而是锁定整个表。其次,据我所知,是通过除nativ之外的其他特定于应用程序的方式实现的
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;