SELECT FOR UPDATE 用于锁定查询

Posted

技术标签:

【中文标题】SELECT FOR UPDATE 用于锁定查询【英文标题】:SELECT FOR UPDATE for locked queries 【发布时间】:2008-12-25 07:53:23 【问题描述】:

我正在使用 mysql 5.x,在我的环境中,我有一个名为 CALLS 的表。

表 CALLS 有一个列状态,它采用枚举 inprogress, completed。

我希望表的读取/更新是行锁定的,所以:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET AUTOCOMMIT = 0;
SELECT amount from CALLS where callId=1213 FOR UPDATE;
COMMIT

基本上,即使在我只需要读取金额并返回的情况下,我也会执行 FOR UPDATE。我发现这使我能够确保防止读取/更新相互干扰。但是我被告知这会降低应用程序的并发性。

有没有办法在不产生锁定开销的情况下实现相同的事务一致性?谢谢。

【问题讨论】:

【参考方案1】:

免责声明:MySQL 通常充满惊喜,因此以下内容可能不真实。

您所做的对我来说没有任何意义:您是在 SELECT 之后提交的,这应该会破坏锁定。所以在我看来,你的代码不应该真的产生任何显着的开销。但它也没有给你任何一致性改进。

一般来说,SELECT FOR UPDATE 可以是一种非常合理且合理的方式来确保一致性,而不会占用比实际需要更多的锁。但当然,它只应在需要时使用。也许您应该有不同的代码路径:一个(使用 FOR UPDATE)在检索到的值用于后续更改操作时使用。另一个(不使用 FOR UPDATE)在不需要保护值免受更改时使用。

【讨论】:

我想我终于明白何时需要 FOR UPDATE。如果我在进行修改之前查询一些列并对检索到的值做出一些决定;那么 FOR UPDATE 是合适的。例如保持我自己的自动增量表。【参考方案2】:

你在那里实现的——如果你不熟悉它——被称为pessimistic locking。你为了一致性而牺牲了性能,这有时是一个有效的选择。根据我的专业经验,我发现悲观锁定的障碍远大于帮助。

一方面,它可以导致deadlock。

(更好的恕我直言)替代方案是optimistic locking,您可以假设碰撞很少发生,并且您只需在它们发生时处理它们。您正在处理事务,因此冲突不应使您的数据处于不一致的状态。

这里有更多关于 Java 意义上的 optimistic locking 的信息,但这些想法适用于任何事情。

【讨论】:

对表的修改是金融交易,不能不一致。否则我的公司会因此而赔钱。这就是我使用悲观锁定的动机。

以上是关于SELECT FOR UPDATE 用于锁定查询的主要内容,如果未能解决你的问题,请参考以下文章

for update被锁定解锁

锁定数据行 for update和for update nowait

在 SQL Server 中,如何以类似于 Oracle 的“SELECT FOR UPDATE WAIT”的方式锁定单行?

sql的for update

Oracle 锁定与 SELECT...FOR UPDATE OF

mysql select for update 啥时候解除锁定 ? 就是说 是否要等到java的connection,commit了或者rollback