1. 程式人生 > >Phalcon只更新改變的欄位

Phalcon只更新改變的欄位

前言

之前官網做了一次改版,執行一年多的時間,狀態良好。在效能和抗壓程度上都有了比較大的提升。

然而,在對接了 TMS(第三方配送系統) 和電子發票之後,會經常發生訂單狀態異常的情況。

問題

經過老大和慧哥的分析(我參與了問題的解決,未參與分析),流程如下:

  • 配送員在 TMS 操作訂單完成(完成中);
  • 開電子發票的指令碼獲取了訂單的資訊;
  • TMS 更新完成,訂單狀態發生改變;
  • 開電子發票的指令碼重新更新了訂單的資訊,訂單被變更為 TMS 更新之前的狀態。

正常的 Phalconupdate 流程如下:

$robot = Robots::findFirstById($id
); $robot->name = 'wali'; $robot->update(); // ------- or ------- $robot = Robots::findFirstById($id); $robot->update(['name' => 'wali']);

理想中的 SQL 語句:

UPDATE `robots` SET `name` = 'wali' WHERE `id` = 1

現實中的 SQL 語句:

UPDATE `robots` SET `name` = 'wali', `model` => '1' WHERE `id`
= 1

也就是說 Phalcon 會將取到的所有資料都更新一次。

如果在A取到結果之後,B也操作並更新了這個記錄之後,A再更新,那麼B的操作就相當於沒有做,這就造成了上面的尷尬一幕。

解決

解決方案有好幾個,我會從最不建議的方式開始。

使用白名單

Phalcon 更新一條記錄的過程中,會呼叫 model 類中的 save 方法,而 save 方法提供了一個引數 whiteList,在 whiteList 之內的欄位是不會被更新的。

優點:可以限制某些欄位的更新。

缺點:針對當前情況,需要在每一處操作限制,而且需要更改 update 的方式為 save,工作量太大。

自己寫SQL

可以獲取寫服務之後,直接 execute SQL 語句,這樣可以避免所有欄位更新的情況。

優點:適合批量更新或者多表更新的情況。

缺點:和第一種方案一樣,需要修改每一處地方,工作量大。

設定只更新變化的欄位

Phalcon 本身還是提供了只更新變化欄位的方法的,呼叫也很簡單,在 Model 初始化時,呼叫 useDynamicUpdate 方法,引數為 true

public function initialize()
{
    $this->useDynamicUpdate(true); // 就是它,神奇的方法
    $this->setReadConnectionService('slave');
    $this->setWriteConnectionService('master');
    $this->setSource($this->_tableName);
}

優點:便捷,快速,改動地方少。

缺點:當然是有的,不過我沒有想到…

總結

有些雷,會在不知不覺中埋下,所以對於未知的東西,還是要多瞭解,才能夠作出更加正確的決定。