文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
手冊頁 (TGZ) - 258.5Kb
手冊頁 (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  函數與運算子  /  鎖定函數

14.14 鎖定函數

本節描述用於操作使用者層級鎖定的函數。

表格 14.19 鎖定函數

名稱 說明
GET_LOCK() 取得具名鎖定
IS_FREE_LOCK() 具名鎖定是否為可用
IS_USED_LOCK() 具名鎖定是否正在使用中;如果為真,則傳回連線識別碼
RELEASE_ALL_LOCKS() 釋放所有目前的具名鎖定
RELEASE_LOCK() 釋放具名鎖定

  • GET_LOCK(str,timeout)

    嘗試取得名稱由字串 str 給定的鎖定,使用 timeout 秒的逾時時間。負數的 timeout 值表示無限逾時。鎖定是獨佔的。當某個工作階段持有鎖定時,其他工作階段無法取得相同名稱的鎖定。

    如果成功取得鎖定,則傳回 1;如果嘗試逾時(例如,因為另一個用戶端先前已鎖定名稱),則傳回 0;如果發生錯誤(例如,記憶體不足或執行緒被 mysqladmin kill 終止),則傳回 NULL

    使用 GET_LOCK() 取得的鎖定會透過執行 RELEASE_LOCK() 明確釋放,或在工作階段終止時隱含釋放(無論是正常或異常終止)。使用 GET_LOCK() 取得的鎖定,不會在交易認可或回復時釋放。

    GET_LOCK() 是使用中繼資料鎖定 (MDL) 子系統實作的。可以取得多個同時鎖定,而且 GET_LOCK() 不會釋放任何現有鎖定。例如,假設您執行這些陳述式

    SELECT GET_LOCK('lock1',10);
    SELECT GET_LOCK('lock2',10);
    SELECT RELEASE_LOCK('lock2');
    SELECT RELEASE_LOCK('lock1');

    第二個 GET_LOCK() 會取得第二個鎖定,而且兩個 RELEASE_LOCK() 呼叫都會傳回 1 (成功)。

    甚至某個工作階段也可以取得相同名稱的多個鎖定。其他工作階段無法取得該名稱的鎖定,直到取得鎖定的工作階段釋放該名稱的所有鎖定為止。

    在效能綱要 metadata_locks 表格中,會顯示使用 GET_LOCK() 取得的唯一具名鎖定。OBJECT_TYPE 資料行會顯示 USER LEVEL LOCK,而 OBJECT_NAME 資料行則會指出鎖定名稱。在為相同名稱取得多個鎖定的情況下,只有該名稱的第一個鎖定會在 metadata_locks 表格中註冊一個資料列。該名稱的後續鎖定會遞增鎖定中的計數器,但不會取得其他中繼資料鎖定。當該名稱的最後一個鎖定執行個體釋放時,就會刪除該鎖定的 metadata_locks 資料列。

    取得多個鎖定的功能表示用戶端之間可能發生死結。當發生這種情況時,伺服器會選擇一個呼叫者,並以 ER_USER_LOCK_DEADLOCK 錯誤終止其鎖定取得要求。此錯誤不會導致交易回復。

    MySQL 會強制鎖定名稱的最大長度為 64 個字元。

    GET_LOCK() 可用於實作應用程式鎖定或模擬記錄鎖定。名稱是在伺服器範圍內鎖定的。如果某個名稱已在某個工作階段中鎖定,GET_LOCK() 會封鎖另一個工作階段對相同名稱的鎖定所發出的任何要求。這可讓針對特定鎖定名稱達成共識的用戶端,使用該名稱來執行協同建議鎖定。但請注意,這也會讓不屬於協作用戶端集的用戶端,無意或故意鎖定名稱,因而防止任何協作用戶端鎖定該名稱。減少這種情況發生可能性的其中一種方法,是使用特定於資料庫或特定於應用程式的鎖定名稱。例如,使用 db_name.strapp_name.str 形式的鎖定名稱。

    如果有數個用戶端在等待鎖定,則它們取得鎖定的順序是不確定的。應用程式不應假設用戶端取得鎖定的順序與它們發出鎖定要求的順序相同。

    GET_LOCK() 對於基於陳述式的複製是不安全的。如果當 binlog_format 設定為 STATEMENT 時使用此函數,則會記錄警告。

    由於 GET_LOCK() 僅在單一 mysqld 上建立鎖定,因此不適合與 NDB Cluster 一起使用,NDB Cluster 沒有方法在多個 MySQL 伺服器之間強制執行 SQL 鎖定。如需詳細資訊,請參閱第 25.2.7.10 節:「與多個 NDB Cluster 節點相關的限制」

    警告

    由於具有取得多個具名鎖定的功能,因此單一陳述式有可能取得大量鎖定。例如

    INSERT INTO ... SELECT GET_LOCK(t1.col_name) FROM t1;

    這些類型的陳述式可能會產生某些負面影響。例如,如果陳述式執行到一半失敗並回滾,則在失敗點之前取得的鎖定仍然存在。如果目的是插入的列和取得的鎖定之間存在對應關係,則該目的將無法實現。此外,如果鎖定必須以特定順序授予,請注意結果集的順序可能會因優化器選擇的執行計畫而異。由於這些原因,最好將應用程式限制為每個陳述式僅呼叫一次鎖定獲取。

    另一種鎖定介面可以作為外掛服務或一組可載入的函式使用。與 GET_LOCK() 和相關函式提供的介面不同,此介面提供鎖定命名空間和不同的讀取和寫入鎖定。詳細資訊請參閱第 7.6.9.1 節「鎖定服務」

  • IS_FREE_LOCK(str)

    檢查名為 str 的鎖定是否可以自由使用(即未鎖定)。如果鎖定可用(沒有人正在使用鎖定),則傳回 1;如果鎖定正在使用中,則傳回 0;如果發生錯誤(例如參數不正確),則傳回 NULL

    此函式對於基於陳述式的複寫是不安全的。如果當 binlog_format 設定為 STATEMENT 時使用此函式,則會記錄警告。

  • IS_USED_LOCK(str)

    檢查名為 str 的鎖定是否正在使用中(即已鎖定)。如果是,則傳回持有鎖定的用戶端工作階段的連線識別碼。否則,傳回 NULL

    此函式對於基於陳述式的複寫是不安全的。如果當 binlog_format 設定為 STATEMENT 時使用此函式,則會記錄警告。

  • RELEASE_ALL_LOCKS()

    釋放目前工作階段持有的所有具名鎖定,並傳回釋放的鎖定數量(如果沒有,則傳回 0)。

    此函式對於基於陳述式的複寫是不安全的。如果當 binlog_format 設定為 STATEMENT 時使用此函式,則會記錄警告。

  • RELEASE_LOCK(str)

    釋放由字串 str 指定的鎖定,該鎖定是使用 GET_LOCK() 取得的。如果鎖定已釋放,則傳回 1;如果鎖定不是由此執行緒建立的(在這種情況下,鎖定不會釋放),則傳回 0;如果具名鎖定不存在,則傳回 NULL。如果從未呼叫 GET_LOCK() 取得鎖定,或之前已釋放鎖定,則該鎖定不存在。

    使用 RELEASE_LOCK() 時,DO 陳述式很方便。請參閱第 15.2.3 節「DO 陳述式」

    此函式對於基於陳述式的複寫是不安全的。如果當 binlog_format 設定為 STATEMENT 時使用此函式,則會記錄警告。