并发问题

时间:2009-06-01 18:20:18

标签: php mysql pdo propel

在使用MySQL和PHP + Propel 1.3时,我遇到了似乎是并发问题的问题。下面是Propel对象的“save”方法的一个小例子。

public function save(PropelPDO $con = null) {
    $con = Propel::getConnection();
    try {
        $con->beginTransaction();
        sleep(3); // ignore this, used for testing only
        parent::save($con);
        $foo = $this->getFoo(); // Propel object, triggers a SELECT

        // stuff is happening here...

        $foo->save($con);
        $con->commit();
    } catch (Exception $e) {
        $con->rollBack();
        throw $e;
    }
}

问题是$ foo对象。假设我们在很短的时间内一个接一个地调用示例方法。在某些情况下,如果第二个交易是$ foo ...

$foo = $this->getFoo();

......在第一笔交易有机会保存之前......

$foo->save($con);

...第二次交易读取的$ foo将会过时,会发生不好的事情。

如何强制锁定表Foo对象的存储,以便后续事务只有在第一个事务完成后才能从中读取?

编辑:上下文是一个Web应用程序。简而言之,在某些情况下,我希望第一个请求进行一些数据修改(在获取和保存$ foo之间发生)。所有后续请求都不应该进行修改。是否发生修改取决于获取的$ foo状态(表行属性)。如果两个事务获取相同的$ foo,则修改将发生两次导致问题。

2 个答案:

答案 0 :(得分:1)

将此现有行加载到屏幕/应用程序时,也会加载LastChgDate。保存时,使用“AND LastChgDate = thevalue ”。检查更新的受影响行计数,如果为零,则返回错误“其他人已保存此记录”,以及回滚和其他更改。有了这个逻辑,你只能保存一行,如果它与你加载它时相同。对于新行INSERT,这不是必需的,因为它们是新的。

答案 1 :(得分:0)

在MySQL中,我认为您可以使用SELECT FOR UPDATE来完成锁定。

另一种选择是使用GET_LOCK和RELEASE_LOCK MySQL函数调用来创建用于控制对资源的访问的命名锁。

这些方法有一些缺点。我自己并没有非常使用它们,它们是MySQL专用的,但它们可以为你工作。