【问题标题】:FOR UPDATE doesn't seem to lock the row in MySql InnoDBFOR UPDATE 似乎没有锁定 MySql InnoDB 中的行
【发布时间】:2017-02-01 05:14:18
【问题描述】:

MySql = v5.6

表引擎 = InnoDB

我打开了一个 mysql cli。我跑:

START TRANSACTION;

SELECT id FROM my_table WHERE id=1 FOR UPDATE;

然后我打开并运行第二个 cli:

SELECT id FROM my_table WHERE id=1;

我预计它会等到我提交或回滚第一个事务,但它没有,它只是立即恢复行,就好像没有发生行锁定一样。

我进行了另一项测试,在第一个 cli 中更新了 status 字段,但在提交事务之前我看不到第二个 cli 中的更改,证明事务确实有效。

我是误会FOR UPDATE还是做错了什么?

更新:

需要FOR UPDATE第二次SELECT查询

【问题讨论】:

  • 表被锁定且选择为读取功能时可以读取
  • @Rafiq 对不起,我不明白你的意思?
  • 你可以看到这个文档mysqltutorial.org/mysql-table-locking
  • @Rafiq - table 锁定似乎与这个问题无关。 锁定是相关的。

标签: mysql transactions locking innodb rowlocking


【解决方案1】:

你看到的那个动作是有效的。使用“MVCC”,不同的连接可以在行上看到不同的版本。

第一个连接获取了一种锁定类型,该锁定阻止写入,但不阻止读取。如果第二个连接完成了FOR UPDATEINSERT 或其他“写入”类型的操作,它可能会延迟等待释放锁,或者死锁。 (死锁也需要其他锁。)

常见模式

BEGIN;
SELECT ... FOR UPDATE; -- the row(s) you will update in this transaction
miscellany work
UPDATE...;  -- those row(s).
COMMIT;

如果两个线程在“同一”时间在同一行上运行该代码,则第二个线程将停在SELECT..FOR UPDATE。第一个线程完成后,SELECT 将运行,获取新值。一切都很好。

同时,其他线程可以SELECT(无需更新)并获得一些价值。将这些线程视为在事务之前或之后获取值,具体取决于所有线程的确切时间。重要的是这些“其他”线程将看到数据的一致视图——要么没有该事务中的更新被应用,要么所有都已应用。这就是“原子”的意思。

【讨论】:

  • 谢谢瑞克。有没有读锁之类的东西?基本上,该表包含排队的项目,我有多个线程处理它们 - 我不希望一个项目被处理两次。有没有一个 MySql 模式呢?
  • FOR UPDATE 允许读取,但阻止写入。我会在一分钟内补充我的答案。
  • 谢谢!我缺少的关键位是第二个SELECT 查询也必须使用FOR UPDATE。现在按预期工作。
  • 但它们确实需要包含在事务中吗?还是有其他方法?
猜你喜欢
  • 1970-01-01
  • 2011-10-05
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多