我有一个promo_codes
表,可以通过Web应用程序激活。有一个state
列,可以是0表示未激活,1表示激活。如果我用
SELECT FROM promo_codes WHERE state=0 LIMIT 1 FOR UPDATE;
UPDATE promo_codes SET state=1 WHERE id = ?;
第二次交易运行会发生什么:
SELECT FROM promo_codes WHERE state=0 LIMIT 1 FOR UPDATE;
它只是返回下一行,还是阻塞直到第一个事务完成?
我实际上已经开始考虑只根据redis中的行ID设置一个锁,因为它对我来说很明显它是如何工作的,我知道它不会在MySQL中产生任何性能问题,但另一方面,必须有一种干净,高效的方法才能使这项工作完全在SQL中运行。也许我可以先使用UPDATE ... LIMIT 1
,但在这种情况下如何获取促销代码的ID?
答案 0 :(得分:0)
SELECT for UPDATE和LOCK IN SHARE MODE修饰符有效地在READ-COMMITTED隔离模式下运行,即使当前隔离模式是REPEATABLE-READ。这是因为Innodb只能锁定当前版本的行。考虑类似的情况和行被删除。即使Innodb能够在不再存在的行上设置锁定 - 它对你有用吗?不是真的 - 例如,您可以尝试使用SELECT FOR UPDATE更新刚刚锁定的行但是此行已经消失,因此您会在更新您认为已成功锁定的行时遇到意外错误。无论如何,这样做是为了让所有其他决定更加麻烦。
LOCK IN SHARE MODE实际上通常用于绕过多版本化并确保我们正在读取大多数当前数据,并确保无法更改。例如,这可以用于读取行的集合,为其中一些行计算新值并将其写回。如果我们不使用LOCK IN SHARE MODE,我们可能会遇到麻烦,因为在我们向它们写入新值之前可以更新行,这样的更新可能会丢失。