在我的应用程序中,我有两个几乎同时运行的进程并更新相同的AR模型。
当看起来有些过程没有完成时,我正面临着这个错误,但是单独调试它们没有错误。
然后我明白问题可能发生在下一个案例中:
在描述的情况下,进程A将覆盖B写入的所有进程。
B和A都会更新不同的属性。
有没有办法避免这种覆盖?是否有一些机制使AR更新'Dirty'属性而不是所有模型属性?
请不要在不使用AR的情况下向我解释解决方案。我明白了。但我想知道是否有一些解决方案可以让我使用AR正确地进行所需的更新。
感谢。
答案 0 :(得分:2)
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();
}
答案 1 :(得分:2)
我不知道会有什么结果,但这是一个非常危险的想法,请阅读thread
mylocks( '后', '表', '写')
`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 设置信号量== lock
注意强>
不是生产准备好的代码,没有测试可能带有缺陷