2014-01-29 29 views
3

在我的應用程序中,我有兩個幾乎同時運行並更新相同AR模型的進程。Yii ActiveRecord - 是否有辦法只更新髒屬性?

當我看到一些這樣的過程沒有完成時,我正面臨着這個錯誤,但是單獨調試它們並沒有給出任何錯誤。

然後我理解的是,問題可能發生在下一情況下:

  • 方法A選擇行X
  • 方法B選擇行X
  • 方法B更新行X
  • 方法A的更新行X

在描述的情況下,進程A將覆蓋進程B寫入的所有內容。

B和A都更新不同的屬性。

有沒有辦法避免這種覆蓋?是否有一些機制讓AR只更新'髒'屬性而不是所有的模型屬性?

請不要在不使用AR的情況下向我解釋解決方案。我明白。但我想聽聽是否有一些解決方案可以讓我正確地使用AR來完成所需的更新。

謝謝。

+0

你不使用AR的交易測試,因此可能? –

+0

描述的過程請 – sakhunzai

+1

@AliMasudianPour當然,每個進程使用交易,因爲他們都做與其他web服務撥號有關的複雜工作。但TR沒有解決問題 –

回答

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(); 
} 
+0

謝謝,我知道什麼是交易))我非常喜歡你的想法。 –

2

我不知道那是一定會出現的,但這裏是一個非常危險的想法要做到這一點,請閱讀thread

  • 創建另一個表用於鎖定各個模型
  • mylocks(object,object_type,l ock_type),使得它太普通
  • 如記錄將是
  • mylocks( '後', '表', '寫')

    `類柱延伸的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獲得鎖釋放同時插入 再次重置該鎖(借用它,並給它回)這樣

  • 我還沒有處理的髒數據.The想法某事只有一種模式將數據正確地寫入數據庫 其作爲設置信號量==鎖

注意

不生產準備代碼,不具有瑕疵

+0

沒有危險。完全一樣。只是想更新同一行的不同列。但AR本地save()方法更新所有屬性。 –

+0

我的意思是,我的方法很危險;)看看我寫的是什麼,它會讓你知道如何處理這個問題。雖然它的一個粗略的想法 – sakhunzai

相關問題