我有一个应用程序,不幸的是使用遗留的mysql_ *函数与MyISAM表(bleagh ...),所以我不能使用事务。我有代码获得当前余额,检查此余额是否正常,如果是,它将减去数量并保存新余额。
问题是,我最近看到一个实例,其中两个查询获取相同的起始余额,减去数量,然后记录新的余额。由于他们都获得了相同的起始余额,因此两次更新后的期末余额都是错误的。
100 - 10 = 90
100 - 15 = 85
什么时候应该......
100 - 10 = 90
90 - 15 = 75
这些请求相隔几分钟执行,因此我不认为这种差异是由于竞争条件造成的。我的初始是MySQL缓存存储相同的初始查询的结果,以获得平衡。但我读到,如果修改了任何相关的表,则会删除这种类型的缓存。
我很可能通过将所有内容放入一个查询来修复,但我仍然想要解决这个问题。这让我很困惑。如果在修改表时删除缓存,那么发生的事情应该不会发生。有没有人听说过这样的事情,或者对于为什么会发生这种事情有任何想法?
答案 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)
我认为锁定表是您问题的解决方案:)