【问题标题】:MySQL transactions vs lockingMySQL事务与锁定
【发布时间】:2011-12-30 03:00:11
【问题描述】:

此处需要快速提问/澄清。我有一个数据库表,很可能同时更新记录。我正在为应用程序使用 Zend Framework,并且我已经阅读了避免这种情况的两个方向,首先是表锁定(LOCK TABLES test WRITE)或类似的东西,将返回并重新阅读如何做到这一点,如果这是最好的解决方案。第二个是事务: $db->beginTransaction(); ... $db->commit();

现在“假设”我使用的是事务存储引擎,例如 InnoDB,事务似乎是更常见的解决方案。但是,这是否避免了以下情况:

用户A在网页上->提交数据->开始事务->读取行->计算新值->更新行->保存->提交

用户 B 同时在同一个网页上并同时提交数据,现在可以说它几乎是同时的(用户 B 在开始事务和提交用户 A 的事务之间调用更新函数)用户 B 依赖于用户 A 的事务提交的数据,才能实现准确的计算更新记录。

IE:

数据库行中的开始值:5 用户 A 提交值 5。(开始 事务 -> 读取值 (5) -> 添加提交的值 (5+5=10) -> 写入 更新后的值 -> 保存 -> 提交)

用户 B 提交的值为 7。我需要确保 用户 B 的事务读取为 10,而不是 5(如果未完成更新 阅读前)。

我知道这是一个冗长的解释,我很抱歉,我不确定用于简化问题的正确术语。

谢谢

【问题讨论】:

  • 你能做一些像UPDATE table SET value=value+5这样的事情吗?那么就不需要交易了。
  • 这行得通,肯定会让我的生活变得轻松。只有一个我可能会遇到的问题。我进行更新,然后第二个会话在我读取值之前进行更新,我需要将正确的值发送回原始用户。所以这将是一个更新,然后是一个选择来检索当前的“值”。讨厌在读取发生之前进行第二次更新,那么返回的结果将是无效的(或者我不正确)。我担心的原因是数据在更新并返回给用户时必须 100% 保证正确。
  • 我不认为你能 100% 正确。即使您确保读取了正确的值,在您将其发送给用户并释放锁定的那一刻,它也可能已过时。除非您有一个接收实时数据库更新的事件驱动系统,否则无法保证您拥有当前值。 (即使那样,也可能会有明显的延迟。)
  • 我想得越多,为了准确起见,也许更好的解决方案是审计风格,在其中插入带有设置值的记录,然后使用前一条记录读取该记录,然后前一条记录与插入记录之和返回给用户。我意识到“当前”值可能会更新,但这很好,只要保证计算的值是正确的,并且所有添加的审计历史记录也可以作为有用的副作用提供。
  • 那行得通。在这种情况下,您可能需要使用事务。

标签: mysql zend-framework transactions rowlocking


【解决方案1】:

事务不能确保锁定。事务中的整个块被视为对 db 的原子更新(如果在此块的所有先前更改之间发生任何故障,则回滚)。因此,并行运行的两个事务可以更新同一行。

您需要同时使用两者。

Transaction do
 row.lock
 update row
end

看看,如果行级锁定可以让你更轻松。

【讨论】:

  • 我会接受这个答案,纯粹是因为它回答了我最初的问题(快速版本)“交易是否能防止竞争条件”,答案是否定的。我认为 cmets @MichaelMior 帮助我从不同的角度看待我的问题,并提供了一个更可行的解决方案。所以谢谢你们俩/和平!
猜你喜欢
  • 2011-05-12
  • 2014-07-06
  • 2012-07-23
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多