在我的应用程序中,我有2个流程几乎同时运行并更新相同的AR模型。
当看起来某些过程没有完成时,我正面临着这个错误,但分别调试它们没有任何错误。
然后我知道问题可能在下一个情况下发生:
- 处理A选择行X
- 进程b选择行x
- 进程B更新行X
- 处理A更新行X
在描述的情况下,处理A将覆盖所有过程B写作。
B和A更新不同的属性。
有没有办法避免这种覆盖?是否有一些机制可以使AR更新"脏"属性而不是所有模型属性?
请不要在不使用AR的情况下向我解释解决方案。我明白。但是我想听听是否有一些解决方案可以使我正确地使用AR进行正确的更新。
谢谢。
YourTable::model()->updateByPk($id, array(
'field1' => NewVal1,
'field2' => NewVal2,
'field3' => NewVal3
));
并利用交易:
$transaction=Yii::app()->db->beginTransaction();
try
{
//.... SQL executions OR model save()
$transaction->commit();
}
catch(Exception $e) // an exception is raised if a query fails
{
$transaction->rollback();
}
我不知道这将如何发生,但这是一个非常危险的想法,请阅读线程
- 创建另一个用于使用各自模型锁定的表
- mylocks(object,object_type,lock_type),使它太通用
- 例如,记录将是
-
mylocks('post','table','写')
`class Post扩展了ActivereCord {
public static $dirtyData=array(); protected $semaphore=false; //if its locked true, else false protected function hasSemaphore(){ $c = new CDbCriteria; $c->compare('object',$this->getTableName()); $c->compare('object_type','table'); $lock=MyLocks::model()->find($criteria) return $lock!=null; } // public function setSemaphore(){ if($this->semaphore==true) return true ; if($this->hasSemaphore()){ Yii::app()->db->createCommand('LOCK TABLE '.$this->getTableName().' WRITE;')->execute(); //insert a record to MyLocks //insert into mylocks(object,object_type,lock_type) //values ('post' ,'table','WRITE'); $this->semaphore=true; return true; } $this->semaphore=false; return false; } protected function mergeDirtyData(){ //as I am holding write lock i should collect all dirty // data from other models to save it .... } protected function releaseSemaphore(){ if($this->semaphore){ //delete matching from mylocks table -- sorry I am lazy Yii::app()->db->createCommand('UNLOCK TABLES;')->execute(); $this->semaphore=false; $this->mergeDirtyData() return true; } return false; } .... public function beforeSave() { //if I am holding lock - release it if(!$this->releaseSemaphore()){ //probably someone else is holding if($this->hasSemaphore()) //set values to dirtyData //self::dirtyData[]=array(attrA=>valueA,....); return false; // disable saving } return parent::beforeSave(); }
}'
所以这将是您的操作流
//处理A
$postA=Post::model();
...
$postA->setSemaphore();
...更新一些字段
//过程b
$postB=Post::model();
...更新$ Postb的某些字段
$postB->update();
$postA->update()
其他可能无法处理的情况
-
您将无法在读取锁定锁定时插入记录,以便您有为了解决这个问题,请在插入一个时通过进程B释放锁定它重置该再次锁定(借用它并将其还给它),例如
-
我尚未处理dirtydata。这个想法只有一个模型可以正确地将数据写入db当设置信号量==锁
注意
未生产准备代码,可能没有使用缺陷进行测试