文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
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,則不會等待,且如果無法立即取得鎖定,則函式會產生錯誤。

這些鎖定服務函式可用