yii activerecord-是否可以仅更新肮脏的属性



在我的应用程序中,我有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当设置信号量==锁

注意

未生产准备代码,可能没有使用缺陷进行测试