文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美國信紙尺寸) - 40.0Mb
PDF (A4) - 40.1Mb
手冊頁 (TGZ) - 258.2Kb
手冊頁 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


7.6.9.1 鎖定服務

MySQL 發行版本提供一個鎖定介面,可在兩個層級存取

  • 在 SQL 層級,作為一組可載入函數,每個函數都對應到對服務常式的呼叫。

  • 作為 C 語言介面,可從伺服器外掛程式或可載入函數作為外掛程式服務呼叫。

有關外掛程式服務的一般資訊,請參閱第 7.6.9 節「MySQL 外掛程式服務」。有關可載入函數的一般資訊,請參閱新增可載入函數

鎖定介面具有以下特性

  • 鎖定具有三個屬性:鎖定命名空間、鎖定名稱和鎖定模式

    • 鎖定由命名空間和鎖定名稱的組合識別。命名空間允許不同的應用程式使用相同的鎖定名稱,而不會因在不同的命名空間中建立鎖定而發生衝突。例如,如果應用程式 A 和 B 分別使用 ns1ns2 的命名空間,則每個應用程式都可以使用鎖定名稱 lock1lock2,而不會干擾另一個應用程式。

    • 鎖定模式為讀取或寫入。讀取鎖定是共用的:如果工作階段對給定的鎖定識別碼具有讀取鎖定,則其他工作階段可以取得對相同識別碼的讀取鎖定。寫入鎖定是獨佔的:如果工作階段對給定的鎖定識別碼具有寫入鎖定,則其他工作階段無法取得對相同識別碼的讀取或寫入鎖定。

  • 命名空間和鎖定名稱必須為非 NULL、非空白,且最大長度為 64 個字元。指定為 NULL、空字串或長度超過 64 個字元的字串的命名空間或鎖定名稱會導致 ER_LOCKING_SERVICE_WRONG_NAME 錯誤。

  • 鎖定介面將命名空間和鎖定名稱視為二進位字串,因此比較是區分大小寫的。

  • 鎖定介面提供取得鎖定和釋放鎖定的函數。呼叫這些函數不需要特殊權限。權限檢查是呼叫應用程式的責任。

  • 如果鎖定不是立即可用,則可以等待鎖定。鎖定取得呼叫會採用一個整數逾時值,表示在放棄取得鎖定之前要等待多少秒。如果在沒有成功取得鎖定的情況下達到逾時,則會發生 ER_LOCKING_SERVICE_TIMEOUT 錯誤。如果逾時為 0,則不會等待,且如果無法立即取得鎖定,則呼叫會產生錯誤。

  • 鎖定介面會偵測不同工作階段中鎖定取得呼叫之間的死鎖。在這種情況下,鎖定服務會選擇一個呼叫者,並以 ER_LOCKING_SERVICE_DEADLOCK 錯誤終止其鎖定取得要求。此錯誤不會導致交易回滾。為了在發生死鎖時選擇工作階段,鎖定服務會優先選擇持有讀取鎖定的工作階段,而不是持有寫入鎖定的工作階段。

  • 一個連線階段可以使用單一的鎖定獲取呼叫來取得多個鎖定。對於給定的呼叫,鎖定獲取是原子性的:如果所有鎖定都獲取成功,則呼叫成功。如果任何鎖定的獲取失敗,則呼叫不會取得任何鎖定並失敗,通常會出現 ER_LOCKING_SERVICE_TIMEOUTER_LOCKING_SERVICE_DEADLOCK 錯誤。

  • 一個連線階段可以為相同的鎖定識別碼(命名空間和鎖定名稱組合)取得多個鎖定。這些鎖定實例可以是讀取鎖定、寫入鎖定,或兩者的混合。

  • 在連線階段中取得的鎖定,會透過呼叫釋放鎖定函式來明確釋放,或在連線階段終止時(正常或異常)隱含釋放。鎖定不會在交易提交或回滾時釋放。

  • 在連線階段中,當釋放給定命名空間的所有鎖定時,會一起釋放。

鎖定服務提供的介面與 GET_LOCK() 和相關 SQL 函式提供的介面不同(請參閱 第 14.14 節「鎖定函式」)。例如,GET_LOCK() 不會實作命名空間,且僅提供獨佔鎖定,而不是不同的讀取和寫入鎖定。

7.6.9.1.1 鎖定服務 C 介面

本節描述如何使用鎖定服務 C 語言介面。若要改用函式介面,請參閱 第 7.6.9.1.2 節「鎖定服務函式介面」。如需鎖定服務介面的一般特性,請參閱 第 7.6.9.1 節「鎖定服務」。如需關於外掛服務的一般資訊,請參閱 第 7.6.9 節「MySQL 外掛服務」

使用鎖定服務的原始程式碼檔案應包含此標頭檔

#include <mysql/service_locking.h>

若要取得一個或多個鎖定,請呼叫此函式

int mysql_acquire_locking_service_locks(MYSQL_THD opaque_thd,
                                        const char* lock_namespace,
                                        const char**lock_names,
                                        size_t lock_num,
                                        enum enum_locking_service_lock_type lock_type,
                                        unsigned long lock_timeout);

引數具有以下含義

  • opaque_thd:執行緒控制代碼。如果指定為 NULL,則會使用目前執行緒的控制代碼。

  • lock_namespace:一個以 null 結尾的字串,指示鎖定命名空間。

  • lock_names:一個以 null 結尾的字串陣列,提供要取得的鎖定的名稱。

  • lock_numlock_names 陣列中的名稱數量。

  • lock_type:鎖定模式,LOCKING_SERVICE_READLOCKING_SERVICE_WRITE 分別取得讀取鎖定或寫入鎖定。

  • lock_timeout:在放棄前等待取得鎖定的整數秒數。

若要釋放為給定命名空間取得的鎖定,請呼叫此函式

int mysql_release_locking_service_locks(MYSQL_THD opaque_thd,
                                        const char* lock_namespace);

引數具有以下含義

  • opaque_thd:執行緒控制代碼。如果指定為 NULL,則會使用目前執行緒的控制代碼。

  • lock_namespace:一個以 null 結尾的字串,指示鎖定命名空間。

可以使用效能架構在 SQL 層級監控由鎖定服務取得或等待的鎖定。如需詳細資訊,請參閱鎖定服務監控

7.6.9.1.2 鎖定服務函式介面

本節描述如何使用其可載入函式所提供的鎖定服務介面。若要改用 C 語言介面,請參閱 第 7.6.9.1.1 節「鎖定服務 C 介面」。如需鎖定服務介面的一般特性,請參閱 第 7.6.9.1 節「鎖定服務」。如需關於可載入函式的一般資訊,請參閱 新增可載入函式

安裝或解除安裝鎖定服務函式介面

第 7.6.9.1.1 節「鎖定服務 C 介面」中描述的鎖定服務常式不需要安裝,因為它們內建於伺服器中。對於對應到服務常式呼叫的可載入函式而言,則不是如此:函式必須在使用前安裝。本節描述如何執行此操作。如需關於可載入函式安裝的一般資訊,請參閱 第 7.7.1 節「安裝和解除安裝可載入函式」

鎖定服務函式實作於由 plugin_dir 系統變數命名的目錄中的外掛程式庫檔案中。檔案基本名稱為 locking_service。檔案名稱字尾因平台而異(例如,Unix 和類 Unix 系統為 .so,Windows 為 .dll)。

若要安裝鎖定服務函式,請使用 CREATE FUNCTION 陳述式,並根據您的平台調整 .so 字尾(如有必要)

CREATE FUNCTION service_get_read_locks RETURNS INT
  SONAME 'locking_service.so';
CREATE FUNCTION service_get_write_locks RETURNS INT
  SONAME 'locking_service.so';
CREATE FUNCTION service_release_locks RETURNS INT
  SONAME 'locking_service.so';

如果在複寫來源伺服器上使用函式,請在所有複本伺服器上也安裝它們,以避免複寫問題。

一旦安裝,函式會保持安裝狀態,直到解除安裝為止。若要移除它們,請使用 DROP FUNCTION 陳述式

DROP FUNCTION service_get_read_locks;
DROP FUNCTION service_get_write_locks;
DROP FUNCTION service_release_locks;
使用鎖定服務函式介面

在使用鎖定服務函式之前,請根據安裝或解除安裝鎖定服務函式介面中提供的指示安裝它們。

若要取得一個或多個讀取鎖定,請呼叫此函式

mysql> SELECT service_get_read_locks('mynamespace', 'rlock1', 'rlock2', 10);
+---------------------------------------------------------------+
| service_get_read_locks('mynamespace', 'rlock1', 'rlock2', 10) |
+---------------------------------------------------------------+
|                                                             1 |
+---------------------------------------------------------------+

第一個引數是鎖定命名空間。最後一個引數是一個整數逾時,表示在放棄前等待取得鎖定的秒數。之間的引數是鎖定名稱。

對於剛才顯示的範例,函式會取得具有鎖定識別碼 (mynamespace, rlock1)(mynamespace, rlock2) 的鎖定。

若要取得寫入鎖定而非讀取鎖定,請呼叫此函式

mysql> SELECT service_get_write_locks('mynamespace', 'wlock1', 'wlock2', 10);
+----------------------------------------------------------------+
| service_get_write_locks('mynamespace', 'wlock1', 'wlock2', 10) |
+----------------------------------------------------------------+
|                                                              1 |
+----------------------------------------------------------------+

在這種情況下,鎖定識別碼為 (mynamespace, wlock1)(mynamespace, wlock2)

若要釋放命名空間的所有鎖定,請使用此函式

mysql> SELECT service_release_locks('mynamespace');
+--------------------------------------+
| service_release_locks('mynamespace') |
+--------------------------------------+
|                                    1 |
+--------------------------------------+

每個鎖定函式在成功時都會傳回非零值。如果函式失敗,則會發生錯誤。例如,由於鎖定名稱不能為空,因此會發生以下錯誤

mysql> SELECT service_get_read_locks('mynamespace', '', 10);
ERROR 3131 (42000): Incorrect locking service lock name ''.

一個連線階段可以為相同的鎖定識別碼取得多個鎖定。只要不同的連線階段沒有識別碼的寫入鎖定,該連線階段就可以取得任意數量的讀取或寫入鎖定。每個針對識別碼的鎖定請求都會取得新的鎖定。以下陳述式會使用相同的識別碼取得三個寫入鎖定,然後使用相同的識別碼取得三個讀取鎖定

SELECT service_get_write_locks('ns', 'lock1', 'lock1', 'lock1', 0);
SELECT service_get_read_locks('ns', 'lock1', 'lock1', 'lock1', 0);

如果您此時檢查效能架構 metadata_locks 表格,您應該會發現該連線階段持有六個具有相同 (ns, lock1) 識別碼的個別鎖定。(如需詳細資訊,請參閱 鎖定服務監控。)

由於連線階段在 (ns, lock1) 上至少持有一個寫入鎖定,因此沒有其他連線階段可以為其取得鎖定,無論是讀取還是寫入。如果連線階段僅持有該識別碼的讀取鎖定,則其他連線階段可以為其取得讀取鎖定,但不能取得寫入鎖定。

單一鎖定獲取呼叫的鎖定是以原子方式取得,但原子性不適用於跨呼叫。因此,對於類似以下的陳述式,其中針對結果集的每一列呼叫一次 service_get_write_locks(),原子性適用於每個個別呼叫,但不適用於整個陳述式

SELECT service_get_write_locks('ns', 'lock1', 'lock2', 0) FROM t1 WHERE ... ;
注意

由於鎖定服務針對給定鎖定識別碼的每個成功請求傳回個別的鎖定,因此單一陳述式有可能取得大量的鎖定。例如

INSERT INTO ... SELECT service_get_write_locks('ns', t1.col_name, 0) FROM t1;

這些類型的陳述式可能會產生某些不利影響。例如,如果陳述式在執行過程中失敗並回滾,則在失敗點之前取得的鎖定仍然存在。如果目的是讓插入的列與取得的鎖定之間存在對應關係,則無法滿足此目的。此外,如果鎖定以特定順序授予很重要,請注意結果集順序可能會因最佳化工具選擇的執行計畫而異。由於這些原因,最好將應用程式限制為每個陳述式單一鎖定獲取呼叫。

鎖定服務監控

鎖定服務是使用 MySQL 伺服器中繼資料鎖定架構實作的,因此您可以透過檢查效能架構 metadata_locks 表格來監控取得或等待的鎖定服務鎖定。

首先,啟用中繼資料鎖定儀器

mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
    -> WHERE NAME = 'wait/lock/metadata/sql/mdl';

然後取得一些鎖定並檢查 metadata_locks 表格的內容

mysql> SELECT service_get_write_locks('mynamespace', 'lock1', 0);
+----------------------------------------------------+
| service_get_write_locks('mynamespace', 'lock1', 0) |
+----------------------------------------------------+
|                                                  1 |
+----------------------------------------------------+
mysql> SELECT service_get_read_locks('mynamespace', 'lock2', 0);
+---------------------------------------------------+
| service_get_read_locks('mynamespace', 'lock2', 0) |
+---------------------------------------------------+
|                                                 1 |
+---------------------------------------------------+
mysql> SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS
    -> FROM performance_schema.metadata_locks
    -> WHERE OBJECT_TYPE = 'LOCKING SERVICE'\G
*************************** 1. row ***************************
  OBJECT_TYPE: LOCKING SERVICE
OBJECT_SCHEMA: mynamespace
  OBJECT_NAME: lock1
    LOCK_TYPE: EXCLUSIVE
  LOCK_STATUS: GRANTED
*************************** 2. row ***************************
  OBJECT_TYPE: LOCKING SERVICE
OBJECT_SCHEMA: mynamespace
  OBJECT_NAME: lock2
    LOCK_TYPE: SHARED
  LOCK_STATUS: GRANTED

鎖定服務鎖定的 OBJECT_TYPE 值為 LOCKING SERVICE。這與使用 GET_LOCK() 函式取得的鎖定不同,後者的 OBJECT_TYPEUSER LEVEL LOCK

鎖定命名空間、名稱和模式會顯示在 OBJECT_SCHEMAOBJECT_NAMELOCK_TYPE 欄中。讀取和寫入鎖定的 LOCK_TYPE 值分別為 SHAREDEXCLUSIVE

LOCK_STATUS 值對於已取得的鎖定為 GRANTED,對於正在等待的鎖定為 PENDING。如果一個連線階段持有寫入鎖定,而另一個連線階段正在嘗試取得具有相同識別碼的鎖定,則您應該會看到 PENDING

鎖定服務介面函式參考

鎖定服務的 SQL 介面實作了本節中描述的可載入函式。如需使用範例,請參閱 使用鎖定服務函式介面

函式共用這些特性

  • 傳回值在成功時為非零值。否則,會發生錯誤。

  • 命名空間和鎖定名稱必須是非 NULL、非空,且最大長度為 64 個字元。

  • 逾時值必須是整數,表示在放棄並出現錯誤之前,等待取得鎖定的秒數。如果逾時值為 0,則不會等待,且如果無法立即取得鎖定,則函式會產生錯誤。

這些鎖定服務函式可供使用