MySQL Version Tokens

eric0435發表於2020-04-27

MySQL 5.7.8或更高版本的發行版包括版本令牌,該特性支援建立和同步伺服器令牌,應用程式可以使用這些令牌來防止訪問不正確或過時的資料。

版本令牌介面具有這些特徵:
.版本令牌是由用作鍵或識別符號的名稱和一個值組成的對
.版本令牌可以被鎖定。應用程式可以使用令牌鎖向其他協作應用程式表明正在使用令牌,不應該修改它們。
.每個伺服器都建立版本令牌列表;例如,指定伺服器分配或操作狀態。此外,與伺服器通訊的應用程式可以註冊自己的令牌列表,這些令牌表示它需要伺服器處於的狀態。應用程式傳送到不處於所需狀態的伺服器的SQL語句將產生錯誤。這是給應用程式的一個訊號,它應該尋找另一個處於所需狀態的伺服器來接收SQL語句。

以下部分描述了版本令牌的元件,討論瞭如何安裝和使用它,併為其元件提供參考資訊。

版本標識元件
名為version_token的伺服器端外掛持有與伺服器關聯的版本令牌列表,並訂閱語句執行事件的通知。version_token外掛使用審計外掛API來監視來自客戶端的傳入語句,並將每個客戶端特定於會話的版本令牌列表與伺服器版本令牌列表進行匹配。如果存在匹配,外掛允許語句透過,伺服器繼續處理它。否則,外掛將向客戶端返回一個錯誤,語句將失敗。

一組使用者定義函式(udf)提供了一個sql級別的API,用於操作和檢查外掛維護的伺服器版本令牌列表。呼叫任何的令牌udf版本

系統變數允許客戶端指定註冊所需伺服器狀態的版本令牌列表。如果客戶端傳送語句時伺服器處於不同的狀態,則客戶端接收到一個錯誤

安裝或解除安裝版本令牌

這裡介紹如何安裝或解除安裝版本令牌,這些令牌是在包含外掛和使用者定義函式的外掛庫檔案中實現的。有關安裝或解除安裝外掛和udf的一般資訊要使伺服器可用,外掛庫檔案必須位於MySQL外掛目錄中(由plugin_dir系統變數命名的目錄)。如果需要,在伺服器啟動時設定plugin_dir的值,告訴伺服器外掛目錄的位置

外掛庫的基本名是version_token。檔名字尾因平臺而異(例如,對於Unix和類Unix系統,.dll為Windows).

要安裝版本令牌外掛和udf,請使用install plugin並建立函式語句(根據需要調整.so字尾):

mysql> INSTALL PLUGIN version_tokens SONAME 'version_token.so';
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    39
Current database: mysql
Query OK, 0 rows affected (0.07 sec)
mysql> CREATE FUNCTION version_tokens_set RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)
mysql> CREATE FUNCTION version_tokens_show RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)
mysql> CREATE FUNCTION version_tokens_edit RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)
mysql> CREATE FUNCTION version_tokens_delete RETURNS STRING SONAME 'version_token.so';
CREATE FUNCTION version_tokens_lock_shared RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)
mysql> CREATE FUNCTION version_tokens_lock_shared RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION version_tokens_lock_exclusive RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION version_tokens_unlock RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.03 sec)

您必須安裝udf來管理伺服器的版本令牌列表,但是您還必須安裝外掛,因為沒有它udf將無法正常工作。

如果在主複製伺服器上使用外掛和udf,也要將它們安裝在所有從伺服器上,以避免複製問題

如前所述,一旦安裝完成,版本令牌外掛和udf將一直保持安裝狀態,直到解除安裝為止。要刪除它們,使用UNINSTALL外掛和DROP FUNCTION語句:

mysql> uninstall plugin version_tokens;
Query OK, 0 rows affected, 1 warning (0.02 sec)
mysql> drop function version_tokens_set;
drop function version_tokens_show;
Query OK, 0 rows affected (0.02 sec)
mysql> drop function version_tokens_show;
drop function version_tokens_edit;
Query OK, 0 rows affected (0.00 sec)
mysql> drop function version_tokens_edit;
Query OK, 0 rows affected (0.00 sec)
mysql> drop function version_tokens_delete;
Query OK, 0 rows affected (0.01 sec)
mysql> drop function version_tokens_lock_shared;
Query OK, 0 rows affected (0.00 sec)
mysql> drop function version_tokens_lock_exclusive;
Query OK, 0 rows affected (0.00 sec)
mysql> drop function version_tokens_unlock;
Query OK, 0 rows affected (0.02 sec)

使用版本標記
版本令牌可能有用的一個場景是,系統訪問MySQL伺服器集合,但是需要透過監視它們並根據負載變化調整伺服器分配來管理它們,以實現負載平衡。這樣一個系統包括這些元件
.要管理的MySQL伺服器集合
.與伺服器通訊並將它們組織成高可用性組的管理或管理應用程式。組有不同的用途,每個組中的伺服器可能有不同的分配。某個組內的伺服器的分配可以隨時更改
.訪問伺服器以檢索和更新資料的客戶機應用程式,根據分配給它們的用途選擇伺服器。例如,客戶端不應該向只讀伺服器傳送更新

版本令牌允許根據分配對伺服器訪問進行管理,而不需要客戶端重複查詢伺服器的分配
.管理應用程式執行伺服器分配並在每個伺服器上建立版本令牌以反映其分配。應用程式快取此資訊以提供對其的中央訪問點。如果在某個時候管理應用程式需要更改伺服器分配(例如,將其從允許寫改為僅允許讀),則它將更改伺服器的版本令牌列表並更新其快取。

.為了提高效能,客戶端應用程式從管理應用程式獲取快取資訊,使它們不必為每個語句檢索關於伺服器分配的資訊。基於它將發出的語句型別(例如,讀與寫),客戶端選擇適當的伺服器並連線到它

.此外,客戶端向伺服器傳送自己的客戶端特定版本的令牌來註冊它需要的伺服器分配。對於客戶端傳送到伺服器的每個語句,伺服器將自己的令牌列表與客戶端令牌列表進行比較。如果伺服器令牌列表包含客戶端令牌列表中所有具有相同值的令牌,則存在匹配,伺服器執行該語句

另一方面,可能管理應用程式更改了伺服器分配及其版本令牌列表。在這種情況下,新的伺服器分配現在可能與客戶端需求不相容。伺服器和客戶端令牌列表之間的令牌不匹配,伺服器返回一個錯誤作為對語句的應答。這指示客戶機從管理應用程式快取中重新整理其版本令牌資訊,並選擇要與之通訊的新伺服器。

檢測版本令牌錯誤和選擇新伺服器的客戶端邏輯可以透過不同的方式實現:
.客戶端可以自己處理所有版本令牌註冊、不匹配檢測和連線切換
.這些操作的邏輯可以在管理客戶端和MySQL伺服器之間連線的聯結器中實現。這樣的聯結器可以處理錯配錯誤檢測和語句重新傳送本身,也可以將錯誤傳遞給應用程式,並將其留給應用程式重新傳送語句。

下面的例子以更具體的形式說明了前面的討論。
當版本令牌在給定伺服器上初始化時,伺服器的版本令牌列表為空。透過呼叫使用者定義函式(udf)來執行令牌列表維護。呼叫任何版本令牌udf都需要超級特權,因此具有該特權的管理或管理應用程式需要修改令牌列表。

假設一個管理應用程式與一組伺服器通訊,客戶端查詢這些伺服器以訪問僱員和產品資料庫(分別名為emp和prod)。所有伺服器都被允許處理資料檢索語句,但只有一部分伺服器被允許進行資料庫更新。為了在特定於資料庫的基礎上處理這個問題,管理應用程式在每個伺服器上建立一個版本令牌列表。在給定伺服器的令牌列表中,令牌名稱表示資料庫名稱,讀寫令牌值取決於資料庫是否必須以只讀方式使用,或者是否可以進行讀寫。

客戶端應用程式透過設定系統變數來註冊它們需要伺服器匹配的版本令牌列表。變數設定是在客戶端特定的基礎上進行的,因此不同的客戶端可以註冊不同的需求。預設情況下,客戶端令牌列表是空的,它匹配任何伺服器令牌列表。當客戶端將其令牌列表設定為非空值時,匹配可能成功也可能失敗,這取決於伺服器版本令牌列表。

為了定義伺服器的版本令牌列表,管理應用程式呼叫version_token_set() UDF。(稍後將介紹用於修改和顯示令牌列表的udf。)例如,應用程式可能將這些語句傳送到三個伺服器組成的組
伺服器1:

mysql> SELECT version_tokens_set('emp=read;prod=read');
+------------------------------------------+
| version_tokens_set('emp=read;prod=read') |
+------------------------------------------+
| 2 version tokens set.                    |
+------------------------------------------+
1 row in set (0.03 sec)

伺服器2:

mysql> SELECT version_tokens_set('emp=write;prod=read');
+-------------------------------------------+
| version_tokens_set('emp=write;prod=read') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+
1 row in set (0.00 sec)

伺服器3:

mysql> SELECT version_tokens_set('emp=read;prod=write');
+-------------------------------------------+
| version_tokens_set('emp=read;prod=write') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+
1 row in set (0.00 sec)

在每種情況下,令牌列表都被指定為以分號分隔的名稱=值對列表。產生的令牌列表值導致這些伺服器連線:
.任何伺服器都會接受對兩個資料庫中的任意一個進行讀取
.只有伺服器2接受對emp資料庫的更新
.只有伺服器3接受對prod資料庫的更新

除了為每個伺服器分配一個版本令牌列表外,管理應用程式還維護一個反映伺服器分配的快取。

在與伺服器通訊之前,客戶機應用程式與管理應用程式進行聯絡,並檢索關於伺服器分配的資訊。然後客戶端根據這些分配選擇伺服器。假設客戶機希望同時執行對emp資料庫的讀寫操作。根據前面的分配,只有伺服器2合格。客戶機連線到伺服器2,並透過設定
version_tokens_session系統變數在伺服器2上註冊伺服器需求:

mysql> SET @@session.version_tokens_session = 'emp=write';
Query OK, 0 rows affected (0.00 sec)

對於客戶機傳送到伺服器2的後續語句,伺服器將自己的版本令牌列表與客戶機列表進行比較,以檢查它們是否匹配。如果是,則語句正常執行:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4981;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT last_name, first_name FROM emp.employee WHERE id = 4981;
+-----------+------------+
| last_name | first_name |
+-----------+------------+
| Smith | Abe |
+-----------+------------+
1 row in set (0.01 sec)

伺服器和客戶端版本令牌列表之間的差異可能以兩種方式出現:
.version_tokens_session值中的令牌名稱在伺服器令牌列表中不存在。在這種情況下會發生ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND錯誤
.version_tokens_session值中的令牌值與伺服器令牌列表中相應令牌的值不同。在這種情況下將出現ER_VTOKEN_PLUGIN_TOKEN_MISMATCH錯誤

只要伺服器2的分配沒有改變,客戶端就會繼續使用它進行讀寫。但是,假設管理應用程式希望更改伺服器分配,以便emp資料庫的寫操作必須傳送到伺服器1而不是伺服器2。為此,它使用version_tokens_edit()修改兩個伺服器上的emp令牌值(並更新其伺服器分配快取):
伺服器1:

mysql> SELECT version_tokens_edit('emp=write');
+----------------------------------+
| version_tokens_edit('emp=write') |
+----------------------------------+
| 1 version tokens updated.        |
+----------------------------------+
1 row in set (0.00 sec)

伺服器2:

mysql> SELECT version_tokens_edit('emp=read');
+---------------------------------+
| version_tokens_edit('emp=read') |
+---------------------------------+
| 1 version tokens updated.       |
+---------------------------------+
1 row in set (0.00 sec)

version_tokens_edit()修改伺服器令牌列表中的指定令牌而其它的令牌不會改變。

當客戶機下一次向伺服器2傳送一條語句時,它自己的令牌列表將不再與伺服器令牌列表匹配,並出現一個錯誤

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4982;
ERROR 3136 (42000): Version token mismatch for emp. Correct value read

在這種情況下,客戶端應該聯絡管理應用程式以獲得關於伺服器分配的更新資訊,選擇一個新伺服器,並將失敗的語句傳送到新伺服器

注意:每個客戶端必須與版本令牌進行協作,僅根據它在給定伺服器上註冊的令牌列表傳送語句。例如,如果客戶端註冊了一個'emp=read'的令牌列表,版本令牌中沒有任何內容可以阻止客戶端傳送emp資料庫的更新。客戶本身必須避免這樣做

對於從客戶機接收到的每個語句,伺服器隱式地使用鎖,如下所示:
.為客戶端令牌列表(即version_tokens_session值)中命名的每個令牌獲取一個共享鎖
.執行伺服器和客戶端令牌列表之間的比較
.根據比較結果執行語句或產生錯誤
.釋放鎖

伺服器使用共享鎖,以便可以在不阻塞的情況下對多個會話進行比較,同時防止對任何試圖在操作伺服器令牌列表中具有相同名稱的令牌之前獲取獨佔鎖的會話的令牌進行更改

前面的例子只使用了版本標記外掛庫中包含的一些使用者定義,但是還有其他的。一組udf允許對伺服器的版本令牌列表進行操作和檢查。另一組udf允許鎖定和解鎖版本標記

這些udf允許建立、更改、刪除和檢查伺服器的版本標記列表:
.version_tokens_set()完全替換當前列表並分配一個新列表。引數是一個以分號分隔的名稱=值對列表。
.version_tokens_edit()支援對當前列表進行部分修改。它可以新增新的令牌或更改現有令牌的值。引數是一個以分號分隔的名稱=值對列表
.version_tokens_delete()從當前列表中刪除令牌。引數是一個用分號分隔的令牌名稱列表
.version_tokens_show()顯示當前令牌列表。不需要任何論證

這些函式中的每一個,如果成功,將返回一個指示操作發生的二進位制字串。下面的示例建立伺服器令牌列表,透過新增新令牌對其進行修改,刪除一些令牌,並顯示生成的令牌列表:

mysql> SELECT version_tokens_set('tok1=a;tok2=b');
+-------------------------------------+
| version_tokens_set('tok1=a;tok2=b') |
+-------------------------------------+
| 2 version tokens set.               |
+-------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT version_tokens_edit('tok3=c');
+-------------------------------+
| version_tokens_edit('tok3=c') |
+-------------------------------+
| 1 version tokens updated.     |
+-------------------------------+
1 row in set (0.00 sec)
mysql> SELECT version_tokens_delete('tok2;tok1');
+------------------------------------+
| version_tokens_delete('tok2;tok1') |
+------------------------------------+
| 2 version tokens deleted.          |
+------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT version_tokens_show();
+-----------------------+
| version_tokens_show() |
+-----------------------+
| tok3=c;               |
+-----------------------+
1 row in set (0.00 sec)

如果令牌列表格式不正確,就會出現警告:

mysql> SELECT version_tokens_set('tok1=a; =c');
+----------------------------------+
| version_tokens_set('tok1=a; =c') |
+----------------------------------+
| 1 version tokens set.            |
+----------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings \G
*************************** 1. row ***************************
  Level: Warning
   Code: 42000
Message: Invalid version token pair encountered. The list provided is only partially updated.
1 row in set (0.00 sec)

如前所述,版本標記是使用一個以分號分隔的名稱=值對列表來定義的。考慮一下version_tokens_set()的呼叫:

mysql> SELECT version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4');
+---------------------------------------------------------------+
| version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4') |
+---------------------------------------------------------------+
| 3 version tokens set.                                         |
+---------------------------------------------------------------+
1 row in set (0.00 sec)

版本標記對引數的解釋如下:
.名稱和值周圍的空白將被忽略。允許在名稱和值中使用空格。(對於version_tokens_delete(),它接受一個沒有值的名稱列表,名稱周圍的空白將被忽略。)
.沒有報價機制
.令牌的順序並不重要,除非令牌列表包含給定令牌名稱的多個例項,否則最後一個值優先於前面的值

根據這些規則,前面的version_tokens_set()呼叫會產生一個令牌列表,其中包含兩個令牌:tok1的值是1’2 3’4,tok2的值是a = b。

mysql> SELECT version_tokens_show();
+--------------------------+
| version_tokens_show()    |
+--------------------------+
| tok2=a = b;tok1=1'2 3"4; |
+--------------------------+
1 row in set (0.01 sec)

如果令牌列表包含兩個令牌,為什麼version_tokens_set()返回設定的值3版本令牌?這是因為原來的令牌列表包含兩個tok1定義,而第二個定義替換了第一個定義。

版本標記令牌操作udf將這些約束放在令牌名稱和值上:
.令牌名稱不能包含=或;字元,最大長度為64個字元
.令牌值不能包含;字元。值的長度受到max_allowed_packet系統變數的值的限制
.版本令牌將令牌名稱和值視為二進位制字串,因此比較是區分大小寫的

版本令牌還包括一組udf,允許對令牌進行鎖定和解鎖:
.version_tokens_lock_exclusive()獲得獨佔的版本令牌鎖。它接受一個或多個鎖名和超時值的列表
.version_tokens_lock_shared()獲得共享版本令牌鎖。它接受一個或多個鎖名和超時值的列表
.version_tokens_unlock()釋放版本令牌鎖(獨佔和共享)。不需要任何論證

每個鎖定函式都返回非零表示成功。否則,將發生錯誤:

mysql> SELECT version_tokens_lock_shared('lock1', 'lock2', 0);
+-------------------------------------------------+
| version_tokens_lock_shared('lock1', 'lock2', 0) |
+-------------------------------------------------+
| 1 |
+-------------------------------------------------+
mysql> SELECT version_tokens_lock_shared(NULL, 0);
ERROR 3131 (42000): Incorrect locking service lock name '(null)'.

使用版本標記鎖定功能的鎖定是建議的;申請必須同意合作。

可以鎖定不存在的令牌名稱。這不會建立令牌。

對於版本令牌鎖定函式,令牌名稱引數完全按照指定的方式使用。周圍的空白不被忽略,並且=和;字元是允許的。這是因為令牌只是像傳遞
給鎖定服務一樣傳遞要鎖定的令牌名稱。

版本標記引用

版本標記功能
版本令牌外掛庫包含幾個使用者定義的函式。一組udf允許對伺服器的版本令牌列表進行操作和檢查。另一組udf允許鎖定和解鎖版本標記。呼叫任何版本令牌UDF都需要超級特權。

下面的udf允許建立、更改、刪除和檢查伺服器的版本令牌列表:
.version_tokens_delete (name_list)
使用name_list引數從伺服器的版本令牌列表中刪除令牌,並返回指示操作結果的二進位制字串。name_list是要刪除的版本令牌名稱的分號分隔列表。

mysql> SELECT version_tokens_delete('tok1;tok3');
+------------------------------------+
| version_tokens_delete('tok1;tok3') |
+------------------------------------+
| 2 version tokens deleted.          |
+------------------------------------+
1 row in set (0.00 sec)

從MySQL 5.7.9開始,NULL引數被視為空字串,這對令牌列表沒有影響。
version_tokens_delete()刪除其引數中指定的標記(如果它們存在的話)。(刪除不存在的令牌不是錯誤。)要在不知道列表中有哪些令牌的情況下完全清除令牌列表,請將NULL或不包含令牌的字串傳遞給version_tokens_set():

mysql> SELECT version_tokens_set(NULL);
+------------------------------+
| version_tokens_set(NULL)     |
+------------------------------+
| Version tokens list cleared. |
+------------------------------+
1 row in set (0.00 sec)
mysql> SELECT version_tokens_set('');
+------------------------------+
| version_tokens_set('')       |
+------------------------------+
| Version tokens list cleared. |
+------------------------------+
1 row in set (0.00 sec)

.version_tokens_edit (token_list)
使用token_list引數修改伺服器的版本令牌列表,並返回指示操作結果的二進位制字串。token_list是一個以分號分隔的名稱=值對列表,它指定要定義的每個令牌的名稱及其值。如果存在令牌,則使用給定的值更新其值。如果標記不存在,則使用給定的值建立它。如果引數為NULL或字串不包含令牌,則令牌列表保持不變。

mysql> SELECT version_tokens_set('tok1=value1;tok2=value2');
+-----------------------------------------------+
| version_tokens_set('tok1=value1;tok2=value2') |
+-----------------------------------------------+
| 2 version tokens set.                         |
+-----------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT version_tokens_edit('tok2=new_value2;tok3=new_value3');
+--------------------------------------------------------+
| version_tokens_edit('tok2=new_value2;tok3=new_value3') |
+--------------------------------------------------------+
| 2 version tokens updated.                              |
+--------------------------------------------------------+
1 row in set (0.00 sec)

.version_tokens_set (token_list)
用token_list引數中定義的令牌替換伺服器的版本令牌列表,並返回指示操作結果的二進位制字串。token_list是一個用分號分隔的名稱=值對列表,指定要定義的每個令牌的名稱及其值。如果引數為空或字串不包含令牌,則清除令牌列表。

mysql> SELECT version_tokens_set('tok1=value1;tok2=value2');
+-----------------------------------------------+
| version_tokens_set('tok1=value1;tok2=value2') |
+-----------------------------------------------+
| 2 version tokens set.                         |
+-----------------------------------------------+
1 row in set (0.00 sec)

.version_tokens_show()
以二進位制字串的形式返回伺服器的版本標記列表,其中包含一個以分號分隔的名稱=值對列表。

mysql> SELECT version_tokens_show();
+--------------------------+
| version_tokens_show()    |
+--------------------------+
| tok2=value2;tok1=value1; |
+--------------------------+
1 row in set (0.00 sec)

下面的udf允許鎖定和解鎖版本標記:
.version_tokens_lock_exclusive (token_name [token_name]…超時)
獲取一個或多個版本令牌(按名稱指定為字串)上的獨佔鎖,如果未在給定的超時值內獲取鎖,則超時並報錯

mysql> SELECT version_tokens_lock_exclusive('lock1', 'lock2', 10);
+-----------------------------------------------------+
| version_tokens_lock_exclusive('lock1', 'lock2', 10) |
+-----------------------------------------------------+
| 1 |
+-----------------------------------------------------+

這個函式是在MySQL 5.7.8中新增的,名為vtoken_get_write_locks(),在5.7.9中重新命名為version_tokens_lock_exclusive()

.version_tokens_lock_shared (token_name [token_name]…超時)
獲取一個或多個版本令牌(按名稱指定為字串)上的共享鎖,如果未在給定的超時值內獲取鎖,則超時並報錯

mysql> SELECT version_tokens_lock_shared('lock1', 'lock2', 10);
+--------------------------------------------------+
| version_tokens_lock_shared('lock1', 'lock2', 10) |
+--------------------------------------------------+
| 1 |
+--------------------------------------------------+

這個函式是在MySQL 5.7.8中新增的,名為vtoken_get_read_locks(),在5.7.9中重新命名為version_tokens_lock_shared()

.version_tokens_unlock ()
使用version_tokens_lock_exclusive()和version_tokens_lock_shared()釋放在當前會話中獲取的所有鎖。

mysql> SELECT version_tokens_unlock();
+-------------------------+
| version_tokens_unlock() |
+-------------------------+
| 1 |
+-------------------------+

這個函式是在MySQL 5.7.8中新增的,名為vtoken_release_locks(),在5.7.9中重新命名為version_tokens_unlock()。

鎖定功能共享這些特性:
.對於成功,返回值為非零。否則,將發生錯誤
.令牌名稱是字串
.與操作伺服器令牌列表的udf的引數處理不同,令牌名稱引數周圍的空白不會被忽略,並且=和;字元是允許的
.可以鎖定不存在的令牌名稱。這不會建立令牌
.超時值是非負整數,表示在出現錯誤超時之前等待獲取鎖所需的時間(以秒為單位)。如果超時為0,則不存在等待,如果不能立即獲取鎖,則該函式將產生一個錯誤
.版本令牌鎖定功能基於所描述的鎖定服務在Section 28.3.1 鎖服務中描述。

版本令牌系統變數
版本標記支援以下系統變數。這些變數不可用,除非安裝版本令牌外掛

系統變數:
.version_tokens_session
命令列格式:--version-tokens-session=value
變數範圍:Global,Session
動態:Yes
允許的值:型別為字串,預設值為NULL
此變數的會話值指定客戶端版本令牌列表,並指示客戶端會話要求伺服器版本令牌列表具有的令牌。

如果version_tokens_session變數為NULL(預設值)或值為空,則任何伺服器版本令牌列表都是匹配的。(實際上,空值會禁用匹配需求。)

如果version_tokens_session變數有一個非空值,那麼它的值與伺服器版本令牌列表之間的任何不匹配都會導致會話傳送給伺服器的任何語句出錯。在這種情況下會發生失配:
.version_tokens_session值中的令牌名稱在伺服器令牌列表中不存在。在本例中,發生了ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND錯誤
.version_tokens_session值中的令牌值與伺服器令牌列表中相應令牌的值不同。在本例中,將出現ER_VTOKEN_PLUGIN_TOKEN_MISMATCH錯誤

伺服器版本令牌列表中包含沒有在version_tokens_session值中命名的令牌不是不匹配的

假設一個管理應用程式將伺服器令牌列表設定為如下所示:

mysql> SELECT version_tokens_set('tok1=a;tok2=b;tok3=c');
+--------------------------------------------+
| version_tokens_set('tok1=a;tok2=b;tok3=c') |
+--------------------------------------------+
| 3 version tokens set. |
+--------------------------------------------+

客戶端透過設定其version_tokens_session值來註冊它需要伺服器匹配的令牌。然後,對於客戶端傳送的每個後續語句,伺服器將根據客戶
端version_tokens_session值檢查其令牌列表,如果存在不匹配,則產生一個錯誤:

mysql> SET @@session.version_tokens_session = 'tok1=a;tok2=b';
mysql> SELECT 1;
+---+
| 1 |
+---+
| 1 |
+---+
mysql> SET @@session.version_tokens_session = 'tok1=b';
mysql> SELECT 1;
ERROR 3136 (42000): Version token mismatch for tok1. Correct value a

第一個選擇成功是因為客戶端令牌tok1和tok2出現在伺服器令牌列表中,並且每個令牌在伺服器列表中具有相同的值。第二個SELECT失敗是因為,雖然tok1出現在伺服器令牌列表中,但它的值與客戶機指定的值不同

此時,客戶端傳送的任何語句都將失敗,除非伺服器令牌列表發生更改,使其再次匹配。假設管理應用程式按如下方式更改伺服器令牌列表:

mysql> SELECT version_tokens_edit('tok1=b');
+-------------------------------+
| version_tokens_edit('tok1=b') |
+-------------------------------+
| 1 version tokens updated. |
+-------------------------------+
mysql> SELECT version_tokens_show();
+-----------------------+
| version_tokens_show() |
+-----------------------+
| tok3=c;tok1=b;tok2=b; |
+-----------------------+

現在,客戶機version_tokens_session值與伺服器令牌列表匹配,客戶機可以再次成功執行語句:

mysql> SELECT 1;
+---+
| 1 |
+---+
| 1 |
+---+

這個變數是在MySQL 5.7.8中新增的
.version_tokens_session_number
命令列格式:--version-tokens-session-number=N
變數範圍:Global,Session
動態:NO
允許的值:型別為整型,預設值為0
此變數供內部使用。
這個變數是在MySQL 5.7.8中新增的。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26015009/viewspace-2688727/,如需轉載,請註明出處,否則將追究法律責任。

相關文章