小巧、快速、可靠。
擇三。

SQLite C 介面

解鎖通知

int sqlite3_unlock_notify(
  sqlite3 *pBlocked,                          /* Waiting connection */
  void (*xNotify)(void **apArg, int nArg),    /* Callback function to invoke */
  void *pNotifyArg                            /* Argument to pass to xNotify */
);

在共享快取模式下運行時,如果無法取得共享快取或共享快取中個別表格所需的鎖定,資料庫操作可能會因 SQLITE_LOCKED 錯誤而失敗。有關共享快取鎖定的說明,請參閱 SQLite 共享快取模式。這個 API 可用於註冊一個回呼函式,當目前持有所需鎖定的連線釋放鎖定時,SQLite 將會呼叫此函式。此 API 僅在使用已定義 SQLITE_ENABLE_UNLOCK_NOTIFY C 預處理器符號編譯程式庫時才可用。

另請參閱:使用 SQLite 解鎖通知功能

當資料庫連線完成目前的交易(透過提交或回滾)時,共享快取鎖定就會被釋放。

當一個連線(稱為被阻擋的連線)無法取得共享快取鎖定並向呼叫者返回 SQLITE_LOCKED 時,已鎖定所需資源的資料庫連線(阻擋連線)的身分會被儲存在內部。應用程式收到 SQLITE_LOCKED 錯誤後,可以使用被阻擋的連線控制代碼作為第一個參數呼叫 sqlite3_unlock_notify() 方法,以註冊一個回呼函式,當阻擋連線的目前交易結束時,將會呼叫此函式。此回呼函式會從結束阻擋連線交易的 sqlite3_stepsqlite3_close 呼叫中呼叫。

如果在多執行緒應用程式中呼叫 sqlite3_unlock_notify(),則有可能在呼叫 sqlite3_unlock_notify() 時,阻擋連線已經完成了它的交易。如果發生這種情況,則指定的回呼函式會立即從 sqlite3_unlock_notify() 的呼叫中被呼叫。

如果被阻擋的連線嘗試取得共享快取表格上的寫入鎖定,並且有多個其他連線目前持有同一表格上的讀取鎖定,則 SQLite 會任意選擇其中一個連線作為阻擋連線。

被阻擋的連線最多可以註冊一個解鎖通知回呼函式。如果在被阻擋的連線已經註冊解鎖通知回呼函式時呼叫 sqlite3_unlock_notify(),則新的回呼函式會取代舊的回呼函式。如果使用 NULL 指標作為第二個參數呼叫 sqlite3_unlock_notify(),則任何現有的解鎖通知回呼函式都會被取消。被阻擋的連線的解鎖通知回呼函式也可以透過使用 sqlite3_close() 關閉被阻擋的連線來取消。

解鎖通知回呼函式不可重入。如果應用程式從解鎖通知回呼函式內呼叫任何 sqlite3_xxx API 函式,可能會導致程式當機或死結。

除非偵測到死結(見下文),否則 sqlite3_unlock_notify() 一律會返回 SQLITE_OK。

回呼函式呼叫詳細資訊

註冊解鎖通知回呼函式時,應用程式會提供一個 void* 指標,在呼叫回呼函式時會傳遞給它。然而,回呼函式的簽章允許 SQLite 傳遞一個 void* 上下文指標陣列。傳遞給解鎖通知回呼函式的第一個參數是指向 void* 指標陣列的指標,第二個參數是陣列中的項目數。

當阻擋連線的交易結束時,可能有多個被阻擋的連線已經註冊了用於解鎖通知的回呼函式。如果兩個或多個此類被阻擋的連線指定了相同的回呼函式,則不是多次呼叫回呼函式,而是使用被阻擋的連線指定的 void* 上下文指標集合捆綁到一個陣列中,呼叫一次。這讓應用程式有機會排列與已解除阻擋的資料庫連線集合相關的任何動作的優先順序。

死結偵測

假設在註冊解鎖通知回呼 (unlock-notify callback) 後,資料庫會在執行任何進一步動作之前等待回呼發出(一個合理的假設),那麼使用此 API 可能會導致應用程式死結。例如,如果連線 X 正在等待連線 Y 的交易完成,而連線 Y 也同樣在等待連線 X 的交易完成,則兩個連線都將無法繼續,系統可能會無限期地保持死結狀態。

為了避免這種情況,sqlite3_unlock_notify() 會執行死結偵測。如果對 sqlite3_unlock_notify() 的呼叫會使系統進入死結狀態,則會回傳 SQLITE_LOCKED,並且不會註冊解鎖通知回呼。如果連線 A 已註冊在連線 B 的交易完成時收到解鎖通知回呼,而連線 B 也已註冊在連線 A 的交易完成時收到解鎖通知回呼,則系統被認為處於死結狀態。間接死結也會被偵測到,因此如果連線 B 已註冊在連線 C 的交易完成時收到解鎖通知回呼,而連線 C 正在等待連線 A,則系統也被視為處於死結狀態。允許任意層級的間接性。

「DROP TABLE」例外

當對 sqlite3_step() 的呼叫回傳 SQLITE_LOCKED 時,幾乎總是適合呼叫 sqlite3_unlock_notify()。然而,有一個例外。執行「DROP TABLE」或「DROP INDEX」語句時,SQLite 會檢查是否有任何屬於同一個連線的 SELECT 語句正在執行。如果有的話,會回傳 SQLITE_LOCKED。在這種情況下,沒有「阻塞連線」,因此呼叫 sqlite3_unlock_notify() 會導致立即呼叫解鎖通知回呼。如果應用程式然後再次嘗試「DROP TABLE」或「DROP INDEX」查詢,則可能會導致無限迴圈。

解決此問題的一種方法是檢查 sqlite3_step() 呼叫回傳的擴展錯誤碼。如果有阻塞連線,則擴展錯誤碼會設定為 SQLITE_LOCKED_SHAREDCACHE。否則,在特殊的「DROP TABLE/INDEX」情況下,擴展錯誤碼僅為 SQLITE_LOCKED。

另請參閱物件常數函式列表。