在開發基於 DB2 的嵌入式 C 語言專案時,發生一件詭異的事,拿出來與大家分享。為保持測試資料完整性、開發人員資料一致性,並減輕 DB Server 壓力,決定每兩人共用一個 DB 實例——噩夢由此開始。
每當開發人員 A 編譯好程式開始執行,使用同一 DB 實例的開發人員 B 也開始編譯執行,此時 A 就會報出 SQL0818N A timestamp conflict occurred. 類似錯誤。於是 A 重新預編譯、執行,OK 開始測試;而此時 B 又會報出剛才 A 的錯誤。兩人陷入無限輪迴。
初接觸 DB2,對嵌入式開發原理不熟,以為是 DB2 或客戶端出問題,卸載 Quest Central、重裝 DB2,問題依舊。後來查資料總結,終於找出緣由。下圖說明建立套件(package)的過程。
SQLCODE -818 表示「時間戳衝突」。在 DB2 嵌入式 SQL 開發中,預編譯會產生兩個關鍵產出:
每次預編譯都會產生新的時間戳,寫入應用程式與綁定檔。執行時,DB2 會比對應用程式攜帶的時間戳與資料庫套件中儲存的時間戳。若不一致,拋出 -818 錯誤。
共用 DB 實例時,兩人輪流預編譯會不斷覆寫同一套件的時間戳。A 預編譯後,套件時間戳更新為 A 的版本;A 執行時匹配成功。但 B 隨後預編譯,套件時間戳又變成 B 的版本;A 再執行時,應用程式攜帶的舊時間戳與資料庫新時間戳不符,觸發 -818。雙方陷入「預編譯→執行→對方預編譯→自己報錯」的死循環。