軟體使用 SQLite 並且經常出現 DB Lock 錯誤。零訪問程式碼。我們有什麼可以做的嗎?
我為客戶端編寫了一個 API,它接受來自客戶端的訂單並將它們轉換為列印作業,這些作業通過 HTTP 橋接器進入公司的 RIP 軟體。在後端,網橋讀取作業數據並將其寫入 SQLite 數據庫。它將作業儲存在 SQLite 中,然後將其發送到 RIP。當狀態改變時,RIP 與網橋通信。它更新 SQLite 中的記錄,並通過一系列訂閱和 webhook 將狀態更新發送回 API。
橋接器和 RIP 都不會自動清理,並且橋接器一次限制 5,000 個跟踪作業。因此,如果我們在儲存 5,000 個額外作業時嘗試發送作業 #5001,它將失敗。
因此,至少在理論上,解決方案是在工作完成時對其進行清理。這就是我們正在做的事情。當作業完成時,我的 API 將清理任務排入隊列,該任務從單獨的程序執行並請求網橋刪除該作業。
問題就出現在這裡。當我們請求清理時,由於數據庫鎖定錯誤,橋開始送出作業失敗。我們不會刪除活動作業,因此目前正在插入或更新的內容與由於我們的刪除請求而正在刪除的內容之間應該存在零衝突。我只能假設 SQLite 在刪除期間鎖定整個數據庫,而不是只鎖定正在使用的行。這有意義嗎?
從這個軟體的黑匣子外面,我能做些什麼來影響 SQLite 中的這種鎖定行為嗎?
如果不是,我基本上必須通過在我們的 API 所做的一切與在列印模式和清理模式之間切換但從不同步進行的橋接器之間放置一個緩衝區來解決它。這將起作用,但會減慢生產速度,最終需要我圍繞無法處理我們數量的 200,000 美元軟體產品的限制建構一個 hack。
SQLite 本質上是一個單使用者“數據庫”並鎖定整個文件,因此嘗試修改同一個文件的兩個並發程序必然會相互鎖定。在最好的情況下,被鎖定的文件將包含一個表,在最壞的情況下——整個數據庫。您將不得不通過外部化並發作業的管理來解決這個問題。
SQLite 沒有寫並發,即兩個連接不能同時有寫事務。
解決此問題的最簡單方法是將每個連接中的繁忙超時增加到 30 秒,但至少比您的事務通常需要的時間長十倍。
如果您無法更改該軟體配置其連接的方式,那麼您唯一的選擇就是序列化您的請求。