【问题标题】:Do I need (will I ever need) LOCK IN SHARED MODE | FOR UPDATE within a transaction?我需要(我会需要)锁定共享模式吗? FOR UPDATE 在事务中?
【发布时间】:2014-08-21 18:45:37
【问题描述】:

我正在苦苦挣扎,试图了解如何最好地编写我的代码和查询

直截了当地问:我是否需要或将来需要在事务中明确写入 LOCK IN SHARED MODEFOR UPDATEREAD UNCOMMITTED 除外)?

如果我有外键,是否需要显式选择行以将锁定应用于这些行,或者外键定义就足够了?

【问题讨论】:

  • 事务和锁定是完全不同的特性。我认为您应该解释您的确切用例。

标签: php mysql transactions foreign-keys innodb


【解决方案1】:

简短的回答:绝对是的。

完整的答案:这取决于用例。也许在大多数情况下,InnoDb 使用的默认锁就足够了。这些锁确保您的数据在事务中是一致的。但这里有一个需要使用SELECT ... FOR UPDATE 锁定的场景:

假设您正在制作一个 Web 应用程序,其中您的会话数据存储在数据库中。 Race condition is a concern 涉及会话数据。虽然当文件用于存储会话数据时会满足这种担忧,但如果将它们移动到数据库,则您有责任确保请求不会覆盖彼此的会话更改。在这种情况下,您需要使用FOR UPDATE 从 MySQL 读取会话数据,以确保其他请求将等待此会话写回会话并提交事务,然后才能读取它。

[更新]

这是共享模式的一个用例:

当您想确保某些记录在交易结束前保持不变时,共享模式非常有用。例如当您尝试将具有外键的子记录插入父记录时,而父记录已插入到先前的事务中。在这种情况下,您将首先选择锁定在共享模式下的父记录,然后尝试插入子记录,以确保在插入子记录时,父记录仍然存在。这样其他会话仍然可以读取父记录,但没有人可以更改它。这只是我的想法,但在共享模式锁定的所有用例中,这一事实仍然是相同的,即您希望记录保持不变,同时其他人仍可以读取它。

[更新]

关于SERIALIZABLE的事务隔离级别,MySQL's documentation很清楚。如果您以这种方式设置事务级别以及SET autocommit = 0;,那么它与REPEATABLE READ 级别完全一样,并且在最后用LOCK IN SHARE MODE 编写所有选择查询(除非您明确提及FOR UPDATE)。这意味着您将触摸的所有内容(显式或隐式)都将被锁定。那些被选中而没有提及锁或带有LOCK IN SHARED MODE的那些被锁定在共享模式,其余的被锁定在独占模式。

【讨论】:

  • 所以基本上 innodb 锁定所有在事务中使用 LOCK IN SHARED MODE 选择的内容,但是如果您使用 FOR UPDATE 明确地执行此操作,您会获得更好的性能和更少的死锁?
  • 没有。当您在事务中选择一条记录时,没有任何东西被锁定。其他人可以轻松更改该记录。准确地说,在扫描记录时选择锁定记录,但一旦被选中,就会解除锁定。
  • 怎么什么都没有锁定?我尝试在 mysql shell 中使用 REPEATABLE READ,其他事务等待活动事务完成。如果不是锁,那是什么?
  • 我不确定你的测试场景,但我是我的主张。以下是您应该如何测试它,在两个并发会话中启动事务,在第一个会话中选择一行,然后在第二个会话中更新它。 MySQL 根本不会被锁定,更新会继续进行。如果第一个会话尝试更新记录而不是选择它,MySQL 只会锁定第二个会话。
  • 非常感谢您的更新!再一次,我终于开始了解它是如何工作的 :D 如果你不介意,还有一件事。 SERIALIZABLE 隔离级别怎么样?你会推荐它而不是手动锁定吗?随时可以改进您的答案,我认为它用几句话说明了我在整个网络上找不到的东西:D
猜你喜欢
  • 2012-11-15
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
  • 2018-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多