在使用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,则修改将发生两次导致问题。
答案 0 :(得分:1)
将此现有行加载到屏幕/应用程序时,也会加载LastChgDate。保存时,使用“AND LastChgDate = thevalue ”。检查更新的受影响行计数,如果为零,则返回错误“其他人已保存此记录”,以及回滚和其他更改。有了这个逻辑,你只能保存一行,如果它与你加载它时相同。对于新行INSERT,这不是必需的,因为它们是新的。
答案 1 :(得分:0)
在MySQL中,我认为您可以使用SELECT FOR UPDATE来完成锁定。
另一种选择是使用GET_LOCK和RELEASE_LOCK MySQL函数调用来创建用于控制对资源的访问的命名锁。
这些方法有一些缺点。我自己并没有非常使用它们,它们是MySQL专用的,但它们可以为你工作。