代码之家  ›  专栏  ›  技术社区  ›  Peter

在使用PHP脚本更新具有打开/挂起事务的DB表时,如何避免无限期阻塞?

  •  3
  • Peter  · 技术社区  · 15 年前

    我发现,如果我通过sqlplus修改了表X,并且没有提交更改,那么如果我的Web应用程序(在modphp模式下作为apache下的php脚本运行)试图提交对表X的更改,它将无限期阻塞,直到我通过sqlplus提交更改。

    这种行为是正确的,但我想要的是一种干净/可靠/简单的方法,让我的Web应用程序在n秒后超时,并发出HTTP409错误,而不是无限期阻塞。

    我的第一个想法是使用PCNTL_警报(n)和一个信号处理程序在n秒后捕捉信号。但我发现pcntl_*函数通常在编译时从modphp apache模块中删除,大概是为了避免混淆根apache进程本身用来控制其子进程的信号。也许吧。 应该 为了对通过modphp运行的PHP脚本造成危害,以处理它们自己的sigarlms,但这不是我现在想和我的操作团队选择的一场战斗,所以我必须拒绝这种方法。

    我的第二个想法是,每当应用程序需要修改表X时,都要分叉/启动子进程,并让父进程轮询子进程(可能通过管道上的select())直到操作完成(成功)或N秒(超时+失败)。

    第二种方法 工作,但它给我的印象是丑陋、复杂和脆弱。

    考虑到PHP版本5.2.11和Apache版本1.3.41(在Linux 2.6.9上)的限制,有人知道更好的方法吗?

    2 回复  |  直到 15 年前
        1
  •  2
  •   zombat    15 年前

    我认为对于这种情况,我将尝试直接控制查询超时。最好的方法是使用PHP的mysqli模块,而不是mysql模块,因为这样您就可以访问 mysqli::options 功能。

    使用mysqli::options,可以根据每个连接将查询超时值设置为所需的任何值。一旦超时,您就可以在代码发生错误时将其作为正常流的一部分进行控制。

    如果你不能使用mysqli(或者你没有使用mysql 5),你可以在mysql选项中直接设置这个值,但是这当然会对你的应用产生更大的影响。

    编辑

    作为对你的评论的回应,我认为这可能行不通。这是我刚想到的笨重的东西,但可能会让你过去。

    这个 set_time_limit() 函数可以对PHP脚本的执行设置总的时间限制,如果达到该限制,将触发一个PHP致命错误。但是,当你调用它时,计时器重置为零…并且可以处理PHP致命错误。

    您可以编写自己的错误处理函数,在执行问题查询之前,通过 set_error_handler() . 立即呼叫 set_time_limit() ,并运行查询。如果超出时间限制,将触发致命错误,并转到错误处理功能。你可以从那里继续。

    如果没有触发,您可以通过另一个调用重置计时器 设置时间限制() 在查询之后,然后使用 restore_error_handler() 交换默认的错误处理函数。

    就像我说的,笨重,但也许它能起作用?

        2
  •  0
  •   Peter    15 年前

    不幸的是,在modphp+apache下运行时,php似乎不允许使用pcntl_*()函数。在Linux上运行时,PHP本身提供的设置脚本超时的功能只适用于脚本本身所花费的时间, 等待阻塞的数据库查询所花费的时间。

    所以,你 必须 借助于启动新进程(我们不能调用pcntl_fork())的一般策略来“做可能阻塞的事情”,然后让父进程轮询连接并在n秒后放弃。一种方法是使用proc_open(),将php端管道设置为非阻塞(通过stream_set_blocking())和stream_select()轮询循环,该循环在一定时间后中止。

    这在几个层面上都很烦人。首先,必须确保正确地启动子进程,并安全地将所需操作的信息从父进程传递到子进程,然后必须确保轮询逻辑正确地处理各种子进程失败情况,然后必须安全地将信息从子进程传递回父进程,最后必须清理EVE。然后适当地进行Rything(如果父进程在多次迭代中持续存在,这就变得很重要)。这里的复杂性是如此之大,我敢打赌,任何第一次做这件事的人都必须花几个星期的时间来修复bug,然后行为才真正强大。尽管您对轮询频率和错误处理有明确的控制,但是您还拥有与启动新流程相关的成本。

    我承认没有“一刀切”的解决方案 全部的 这类问题,但是 每个人 谁用PHP编写了一个Web应用程序,必须与Oracle数据库进行对话,他曾经或曾经希望“运行查询X,如果在n秒内没有得到响应,就会抛出异常”。所以我觉得这很荒谬 每个人 谁想要这种行为 必须 实现上面描述的整个系统(或者找到已经完成的其他人)。