MySQL SELECT返回旧值

时间:2012-05-01 21:28:32

标签: php mysql caching

我有一个应用程序,不幸的是使用遗留的mysql_ *函数与MyISAM表(bleagh ...),所以我不能使用事务。我有代码获得当前余额,检查此余额是否正常,如果是,它将减去数量并保存新余额。

问题是,我最近看到一个实例,其中两个查询获取相同的起始余额,减去数量,然后记录新的余额。由于他们都获得了相同的起始余额,因此两次更新后的期末余额都是错误的。

100 - 10 = 90
100 - 15 = 85

什么时候应该......

100 - 10 = 90
90 - 15 = 75

这些请求相隔几分钟执行,因此我不认为这种差异是由于竞争条件造成的。我的初始是MySQL缓存存储相同的初始查询的结果,以获得平衡。但我读到,如果修改了任何相关的表,则会删除这种类型的缓存。

我很可能通过将所有内容放入一个查询来修复,但我仍然想要解决这个问题。这让我很困惑。如果在修改表时删除缓存,那么发生的事情应该不会发生。有没有人听说过这样的事情,或者对于为什么会发生这种事情有任何想法?

3 个答案:

答案 0 :(得分:2)

它不太可能是一个查询缓存 - 如果基础数据集已被另一个查询修改,MySQL足够聪明,可以使缓存条目无效。如果查询缓存在过期时保留旧的陈旧值,那么MySQL就完全没用了。

你是否有未完成的未提交交易导致这种情况?如果相关记录没有相应的锁定,您的第二个查询就可以很容易地获取陈旧数据。

答案 1 :(得分:2)

您的应用程序很可能包含陈旧数据。这很好,它是有多少数据库应用程序可以工作,但是当你执行更新时,而不是做这样的事情:

UPDATE account
SET balance = :current_balance - 10
WHERE account_id = 1

你需要做更多这样的事情:

UPDATE account
SET balance = balance - 10
WHERE account_id = 1

这样,您可以使用数据库中的当前余额,即使有人在平均时间内更改了它,而不是依赖过时的应用程序数据。

如果您只想在没有其他人修改过它的情况下更改该值,那么您可以执行以下操作:

UPDATE account
SET balance = balance - 10
WHERE account_id = 1
  AND balance = :current_balance

如果受影响的行数为1,那么您成功了,其他人没有更改记录。但是,如果受影响的行数为0,则其他人更改了记录。然后,您可以从那里决定要做什么。

答案 2 :(得分:1)

我认为锁定表是您问题的解决方案:)