MySQL在高负载,竞争条件下?

时间:2012-02-03 16:25:02

标签: mysql

在我参与的应用程序中,我遇到了似乎是竞争条件的影响。情况如下,通常,负责某些繁重的应用程序逻辑的页面遵循以下格式:

test中选择并确定是否存在与子句匹配的行 如果匹配的行已经存在,我们在这里终止,否则我们继续应用逻辑
使用与我们的初始选择匹配的值插入test表。

通常,这样可以正常工作并将操作限制为单次执行。但是,在高负载和用户滥用的情况下,许多请求是有意发送的,MySQL允许运行许多应用程序逻辑实例,绕过select子句的限制。

似乎实际上是这样的: 从测试中选择
从测试中选择
从测试中选择
(所有通过检查)
插入测试中 插入测试中 插入测试

我认为这是出于效率原因而做的,但它在我的应用环境中有严重的后果。我试图使用Get_Lock()和Release_Lock(),但这似乎不足以在高负载下,因为竞争条件似乎仍然存在。由于应用程序逻辑非常繁重且所涉及的所有表都不具有事务功能,因此也无法进行事务处理。

对于熟悉此行为的人,是否可以关闭此类处理,以便MySQL始终按照接收顺序处理查询?还有另一种方法可以使这些查询成为原子吗?任何有关此事的帮助将不胜感激,我找不到有关此行为的详细记录。

2 个答案:

答案 0 :(得分:2)

这里的问题是,正如你猜测的那样,你有一种竞争条件。

SELECTINSERT必须是一个原子单位。

您执行此操作的方式是通过交易。您无法安全地创建SELECT,返回PHP,并假设SELECT的结果将反映出INSERT时的数据库状态。

如果精心设计的交易(正确的解决方案)正如您所说的那样 - 我仍然强烈推荐它们 - 您将不得不最终INSERT 原子地检查其假设是否仍然为真(例如通过INSERT IF NOT EXISTS,存储过程或在应用程序中捕获INSERT的错误。如果不是,它将中止回到您的PHP代码,这必须启动逻辑。

顺便说一下,MySQL很可能 按照收到的顺序执行请求。通过多个同时连接,可以接收SELECT ASELECT BINSERT AINSERT B。因此,唯一的“解决方案”是一次只允许一个连接 - 这将会破坏您的可扩展性。

答案 1 :(得分:1)

就个人而言,我会以另一种方式进行检查。

尝试插入行。如果它失败了,那么那里已经有了一行。

以这种方式,您检查或复制并在单个查询中插入新行,从而消除了比赛的可能性。