【问题标题】:Mysql transaction not working as expectedMysql 事务未按预期工作
【发布时间】:2013-10-09 17:47:58
【问题描述】:

我已经阅读了很多关于 mysql 和事务的文档,据我了解,当我在 MySQL InnoDB 中使用可重复读取隔离级别并启动事务时,我添加了一些行,当我对这些行进行选择时MySQL 在该事务中看不到它们的行。例如:

function dotransaction() {
  $result = mysqli_query("START TRANSACTION");
  if (!$result) return false;

  $result = mysqli_query("INSERT INTO t (f1,f2) VALUES (1,2)");
  if (!$result) {
    mysqli_query("ROLLBACK");
    return false;
  }

  $result = mysqli_query("INSERT INTO t (f1,f2) VALUES (3,4)");
  if (!$result) {
    mysqli_query("ROLLBACK");
    return false;
  }

  $result = mysqli_query("UPDATE t2 SET f3=(SELECT COUNT(*) AS count FROM t WHERE f1=1) WHERE f4=2");
  if (!$result) {
    mysqli_query("ROLLBACK");
    return false;
  }
}

如果我在 PHP 中执行以下代码,它确实将表 t2 中的字段 f3 更新为 1。但我没想到,因为当我启动事务时,事务从数据库中读取快照,无论我在哪里使用 select 语句,它都使用第一个读取快照,而不是对表的修改。当我从 UPDATE 语句中取出 select 语句时,它也会遇到 count=1。

【问题讨论】:

  • 您应该使用mysqli::begin_transaction() & mysqli::rollback() 而不是查询相关的SQL。确保 mysqli::autocommit 处于关闭状态。
  • 我为什么要使用那个?

标签: php mysql transactions isolation-level


【解决方案1】:

你理解错了。

在事务中对数据所做的更改在该事务中是可见的,因此您的 SELECT 语句将看到更新的行。

但是,这些更改在事务之外是不可见的,因此如果另一个用户同时连接到服务器并查询这些行,他将看到它们处于未更改状态。

【讨论】:

  • 好的,谢谢,在其他地方找不到示例了。该示例表明,当我使用 SELECT .. FOR UPDATE 时,我可以看到插入的行。
  • SELECT FOR UPDATE 有不同的用途。它锁定选定的行,以便其他事务无法修改它们。见dev.mysql.com/doc/refman/5.5/en/innodb-locking-reads.html
  • 但是当我在事务中进行更新时,我是否必须先使用 SELECT ... FOR UPDATE 选择该行,然后才能保存地更新该行?
  • 不,您不必这样做。如果其他事务在您的事务结束之前更改了这些行,您将无法提交。如果您需要让您的事务优先于其他事务,请锁定行。
猜你喜欢
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 2016-02-04
  • 1970-01-01
  • 2012-06-29
  • 1970-01-01
  • 2018-10-05
  • 2023-03-11
相关资源
最近更新 更多