先看見衝突 再談誰最後寫入
兩個操作員同時打開設定頁,看到的可能都是同一個舊值。只顯示最後寫入者不能防止互相覆蓋,還需要在提交時檢查版本。本文用設定值50.0、版本7的例子,帶你把讀取基準、草稿與實際提交結果分開。
甲與乙都讀到50.0、version=7。甲準備改55.0,乙準備改52.0。若服務只是收到誰就寫誰,乙稍晚送出可能蓋掉甲,而乙根本沒看過55.0。畫面因此要帶基準版本,讓執行端能拒絕過期修改並顯示差異。
保存欄位至少包含設備、參數、值、單位、版本、最後成功寫入者、提交時間及操作識別。最後寫入者必須來自已驗證的使用者身分,不信任客戶端任意填入的名字;時間由權威服務記錄,不能靠兩台HMI牆鐘判定提交先後。
適用於由同一服務管理設定的HMI或上位機。PLC若沒有版本化或條件寫入功能,外層服務可以管理入口,但必須盤點其他寫入通道;工程軟體或另一台HMI直接改PLC時,單一服務的版本便不能代表設備全部變更。
用條件提交保護已讀取的版本
甲送出新值55.0並帶expected_version=7。服務在同一原子判定中確認目前仍7,才更新值、版本8、寫入者甲與提交時間。乙稍後帶expected_version=7送52.0,因目前已8而被拒絕,不能先寫52.0再補查版本。
若使用資料庫,這類條件更新可在一個UPDATE中把主鍵及版本放入條件,並檢查實際更新筆數。更新一筆代表本次條件符合;零筆可能是版本衝突,也可能資料不存在或已被刪除,需再查明原因,不能全部顯示成功。
版本不是顯示用的時間戳。兩次提交可能落在相同毫秒,因此時間相等不能當同一版;版本需由權威端遞增或使用等價不可混淆的修訂識別。重啟、還原備份與計數回繞時,也要避免舊版本再次代表新內容。
若服務提供HTTP資源,可依實際API契約使用強ETag與If-Match條件請求,在資源未符合前提時拒絕修改。這是HTTP層的功能,不是每個PLC模組都支援;不能看到一個版本欄就自行假定有相同原子保證。
把值、版本、最後寫入者與時間一起更新,避免先寫值、後補名字造成混搭。若稽核記錄與設定資料必須一致,也應在同一可靠提交邊界保存,或明確設計可恢復的事件機制。
衝突畫面要提供可理解的選擇
乙遇到衝突時,畫面列出原基準50.0、目前55.0、目前寫入者甲及乙的草稿52.0。提示「設定已被其他使用者更新,本次尚未套用」,並提供重新讀取、保留草稿及捨棄草稿等選擇;不要只有一個模糊的通訊錯誤。
乙若仍希望改成52.0,應先看過目前55.0,再基於版本8建立新的提交意圖。服務仍以版本8作條件檢查;若期間又有人改成版本9,再次衝突是正常保護,不能為了方便自動移除版本條件。
不要把「強制覆蓋」當成一般重試。若產品確實允許,應是另一個有明確權限、差異提示與稽核理由的操作;仍須知道覆蓋哪個設備及哪一版。本文普通流程採重新核對後提交,不在背景靜默重送。
即時顯示別人正在編輯可減少衝突,但這只是協作提示,不是排他保證。使用者可能掉線,編輯租約也可能到期;執行端仍要做條件判定。反過來,鎖住整個畫面很久,也可能讓其他人無法處理必要工作。
若修改不同參數,要先決定版本範圍。每個欄位一版可減少不相關衝突,但跨欄位約束可能需要整份配方一起驗證;例如上下限必須成對一致,不能因為分別改不同欄位就忽略彼此關係。
把服務提交與設備完成分開記錄
資料庫更新成功不一定表示PLC已套用。若服務要再透過通訊把值送設備,應另列Accepted、Sending、Applied與OutcomeUnknown等自訂狀態。畫面可顯示「甲已提交55.0,設備結果待確認」,不能在資料庫成功時就顯示機台已完成。
設備成功回覆或讀回驗證後,才按介面契約記錄已套用版本與設備確認時間。單純讀到55.0也未必證明是甲的這筆操作,因為其他入口可能寫入相同值;有操作識別或設備版本時,應一起核對。
若逾時後結果不明,保留operation_id與狀態,不把最後成功寫入者改成重試的帳號,也不要自動用新操作再寫一次。結果查詢與新的修改是兩件事;前者找原操作結果,後者需要新的版本與意圖。
驗收可安排甲乙同時提交版本7,預期最多一筆在該版本條件下成功,另一筆衝突。再測同一操作重送、相同毫秒提交、服務重啟、設備回覆遺失及外部直接改值,確認每種情況都能看出目前設定與未完成工作。
失敗時先查expected_version、目前version、更新筆數和operation_id,再查顯示快取。若兩筆都宣稱以版本7成功,先找原子條件是否真正生效、是否有繞過服務的寫入路徑,不能只靠調整畫面刷新頻率。
完成後應看到的結果與常見問題
完成畫面應同時呈現目前設定、最後成功提交者與時間、設備套用狀態,以及自己尚未提交的草稿。稽核紀錄則能重建甲55.0成功、乙52.0衝突的順序,並說明乙後來是否基於新版本重新修改。
練習:甲先將版本7更新為8;乙重新讀取8後送52.0,在沒有其他變更時應更新成版本9。最後提交者為乙,但版本8的甲與55.0歷史仍存在;最後一筆資訊不能取代完整變更紀錄。
問:以HMI時間比較誰最後按按鈕可以嗎?答:不能作權威提交順序,時鐘與網路延遲可能不同;以可信任端的版本與受理紀錄判定。
問:只顯示最後寫入者就能防覆蓋嗎?答:不能,還要在真正提交時做原子版本條件檢查。
問:版本衝突就自動重試新版本可以嗎?答:本例不允許,先讓使用者看目前值與差異,確認新的修改意圖。
問:資料庫成功就代表PLC成功嗎?答:不一定,需另外追蹤設備確認及讀回結果,未知時明確顯示待查。
本文已核對條件更新與HTTP前提的背景文件,數字為教學案例。實作前需確認所有寫入入口、權限及設備支援能力。
參考:PostgreSQL UPDATE官方文件:條件更新與受影響筆數背景,非PLC指令。
參考:RFC9110:If-Match及條件請求語意,需實際HTTP API支援。