Apache,MySQL和PHP的竞争条件

时间:2013-03-08 01:01:34

标签: php mysql apache

我的理解是Apache为每个传入请求创建一个单独的PHP进程。这意味着如果我的代码类似于:

  1. 检查记录是否存在
  2. 如果记录不存在,请创建
  3. 然后这很容易受到竞争条件的影响,不是吗?如果两个请求同时进入,并且它们同时命中(1),则它们都将返回false,然后两者都尝试插入新记录。

    如果是这样,人们如何处理这个问题?围绕这两个请求创建一个MySQL事务会解决问题,还是我们需要做一个完整的表锁?

4 个答案:

答案 0 :(得分:2)

据我所知,您无法跨不同的连接创建事务。也许一个解决方案是设置您要检查的列是唯一的。这样,如果与10建立了两个连接,则10不存在。他们都会尝试创建10。首先完成插入行,一切都很顺利;然后只有一秒后面的连接将失败,因为该列不是唯一的。如果捕获引发的异常,则随后可以SELECT来自数据库的记录。

答案 1 :(得分:1)

老实说,我很少遇到这种情况。通常,可以通过重新评估业务需求来缓解这种情况。即使两个不同的用户试图插入完全相同的数据,我也会推迟管理重复用户,而不是应用程序。

但是,如果有理由在应用程序逻辑中强制执行唯一约束,我会使用INSERT IGNORE... ON DUPLICATE KEY UPDATE...查询(当然,在表中使用相应的UNIQUE索引)。

答案 2 :(得分:0)

我认为第二步处理错误应该足够了。如果两个进程尝试创建记录,那么只要您正确配置了MySQL表,其中一个进程就会失败。在正确的字段中使用UNIQUE是一种方法。

答案 3 :(得分:0)

Apache没有“为每个传入请求创建单独的PHP进程”。 它使用进程池(默认,prefork模式)或线程。

正如您所提到的,竞争条件也可能被称为(或导致)DB“死锁”。 @see what is deadlock in a database?

在需要的地方使用交易可以解决这个问题,是的 通过确保检查记录是否存在并在事务中创建它,整个操作都是原子操作 因此,其他请求不会尝试创建重复记录(或者,根据实际查询,创建不一致或输入实际死锁)。

另请注意,MySQL(尚未)支持嵌套事务: 您不能在事务中拥有事务,因为第一个提交将提交所有内容。