int
mysql_session_track_get_first(MYSQL *mysql,
enum enum_session_state_type type,
const char **data,
size_t *length)
MySQL 實作了一種會話追蹤機制,伺服器會將會話狀態變更的相關資訊傳回給客戶端。為了控制伺服器針對狀態變更提供的通知,客戶端應用程式會設定名稱格式為 session_track_
的系統變數,例如 xxx
session_track_state_change
、session_track_schema
和 session_track_system_variables
。請參閱伺服器追蹤用戶端會話狀態。
變更通知發生在 MySQL 客戶端/伺服器協定中,該協定在 OK 封包中包含追蹤器資訊,以便可以偵測到會話狀態變更。為了讓客戶端應用程式能夠從 OK 封包中擷取狀態變更資訊,MySQL C API 提供了一對函數
mysql_session_track_get_first()
提取從伺服器接收到的狀態變更資訊的第一部分。mysql_session_track_get_next()
提取從伺服器接收到的任何剩餘狀態變更資訊。在成功呼叫mysql_session_track_get_first()
之後,只要此函數傳回成功,就重複呼叫此函數。
mysql_session_track_get_first()
的參數使用方式如下。這些說明也適用於 mysql_session_track_get_next()
,它採用相同的參數。
mysql
:連線處理常式。-
type
:追蹤器類型,指出要擷取哪種資訊。允許的追蹤器值是在mysql_com.h
中定義的enum_session_state_type
列舉的成員。enum enum_session_state_type { SESSION_TRACK_SYSTEM_VARIABLES, /* Session system variables */ SESSION_TRACK_SCHEMA, /* Current schema */ SESSION_TRACK_STATE_CHANGE, /* Session state changes */ SESSION_TRACK_GTIDS, /* GTIDs */ SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /* Transaction characteristics */ SESSION_TRACK_TRANSACTION_STATE /* Transaction state */ };
隨著 MySQL 實作額外的會話資訊追蹤器,該列舉的成員可能會隨著時間而變更。為了方便應用程式循環遍歷所有可能的追蹤器類型,而不考慮成員的數量,
SESSION_TRACK_BEGIN
和SESSION_TRACK_END
符號定義為等於enum_session_state_type
列舉的第一個和最後一個成員。本節稍後顯示的範例程式碼將示範此技術。(當然,如果列舉成員變更,您必須重新編譯您的應用程式,使其能夠考慮新的追蹤器。) data
:const char *
變數的位址。成功呼叫後,此變數會指向傳回的資料,該資料應視為唯讀。length
:size_t
變數的位址。成功呼叫後,此變數會包含由data
參數指向的資料長度。
以下討論說明如何根據 type
值來解譯 data
和 length
值。它還會指出哪個系統變數啟用每個追蹤器類型的通知。
-
SESSION_TRACK_SCHEMA
:此追蹤器類型表示已設定預設結構描述。data
是一個包含新預設結構描述名稱的字串。length
是字串長度。若要啟用此追蹤器類型的通知,請啟用
session_track_schema
系統變數。 -
SESSION_TRACK_SYSTEM_VARIABLES
:此追蹤器類型表示已將一個或多個追蹤的會話系統變數指派一個值。當指派會話系統變數時,每個變數會傳回兩個值 (在個別的呼叫中)。對於第一次呼叫,data
是一個包含變數名稱的字串,而length
是字串長度。對於第二次呼叫,data
是一個包含變數值的字串,而length
是字串長度。預設情況下,會針對這些會話系統變數啟用通知
若要變更此追蹤器類型的預設通知,請將
session_track_schema
系統變數設定為要追蹤變更的逗號分隔變數清單,或設定為*
以追蹤所有變數的變更。若要停用會話變數指派的通知,請將session_track_system_variables
設定為空字串。 -
SESSION_TRACK_STATE_CHANGE
:此追蹤器類型表示會話狀態的某些追蹤屬性發生了變更。data
是一個位元組,其中包含一個布林旗標,指出是否發生了會話狀態變更。length
應為 1。旗標表示為 ASCII 值,而不是二進位值 (例如,'1'
,而不是0x01
)。若要啟用此追蹤器類型的通知,請啟用
session_track_state_change
系統變數。此追蹤器會報告會話狀態的這些屬性的變更
預設結構描述 (資料庫)。
系統變數的會話特定值。
使用者定義的變數。
暫時資料表。
預處理陳述式。
-
SESSION_TRACK_GTIDS
:此追蹤器類型表示 GTID 可用。data
包含 GTID 字串。length
是字串長度。GTID 字串採用用於指定一組 GTID 值的標準格式;請參閱GTID 集合。若要啟用此追蹤器類型的通知,請設定
session_track_gtids
系統變數。 -
SESSION_TRACK_TRANSACTION_CHARACTERISTICS
:此追蹤器類型表示交易特性可用。data
是一個包含特性資料的字串。length
是字串長度。特性追蹤器資料字串可以是空的,也可以包含一個或多個 SQL 陳述式,每個陳述式都以分號結尾如果沒有任何特性適用,則字串為空。會套用會話預設值。(對於隔離層級和存取模式,這些預設值由
transaction_isolation
和transaction_read_only
系統變數的會話值給定。)如果交易是明確啟動的,則此字串會包含以相同特性重新啟動交易所需的語句。一般來說,這是一個
START TRANSACTION
語句(可能包含一個或多個READ ONLY
、READ WRITE
和WITH CONSISTENT SNAPSHOT
)。如果任何無法傳遞給START TRANSACTION
的特性適用,例如ISOLATION LEVEL
,則會預先附加一個適當的SET TRANSACTION
語句(例如,SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; START TRANSACTION READ WRITE;
)。-
如果交易不是明確啟動的,但設定了僅適用於下一個交易的一次性特性,則會產生一個適用於複製該設定的
SET TRANSACTION
語句(例如,SET TRANSACTION READ ONLY;
)。可以使用不帶任何
GLOBAL
或SESSION
關鍵字的SET TRANSACTION
,或使用僅適用於下一個交易的語法來設定transaction_isolation
和transaction_read_only
系統變數,來設定下一個交易的特性。SET @@transaction_isolation = value; SET @@transaction_read_only = value;
有關交易特性範圍級別及其設定方式的更多資訊,請參閱交易特性範圍。
若要啟用此追蹤器類型的通知,請將
session_track_transaction_info
系統變數設定為CHARACTERISTICS
(這也會啟用SESSION_TRACK_TRANSACTION_STATE
追蹤器類型)。交易特性追蹤使客戶端能夠確定如何在另一個會話中重新啟動交易,使其具有與原始會話相同的特性。
由於特性可能會在使用
SET TRANSACTION
啟動交易之前設定,因此如果沒有活動交易,客戶端假設沒有交易特性是不安全的。因此,不追蹤交易特性,而僅在沒有活動交易時切換連線(無論是通過交易狀態追蹤器還是傳統的SERVER_STATUS_IN_TRANS
標誌檢測到),都是不安全的。如果客戶端可能希望在某個時刻將其會話切換到另一個連線,並且可能會使用交易,則 必須 訂閱交易特性追蹤器。特性追蹤器追蹤僅適用於下一個交易的一次性特性的變更。它不追蹤會話變數的變更。因此,客戶端還必須追蹤
transaction_isolation
和transaction_read_only
系統變數,以正確確定當下一個交易特性值為空時適用的會話預設值。(要追蹤這些變數,請在session_track_system_variables
系統變數的值中列出它們。) -
SESSION_TRACK_TRANSACTION_STATE
:此追蹤器類型表示交易狀態資訊可用。data
是一個包含 ASCII 字元的字串,每個字元都表示交易狀態的某些方面。length
是字串長度(始終為 8)。若要啟用此追蹤器類型的通知,請將
session_track_transaction_info
系統變數設定為STATE
。交易狀態追蹤使客戶端能夠確定交易是否正在進行中,以及是否可以在不回滾的情況下將其移動到另一個會話。
追蹤器項目的範圍是交易。所有表示狀態的標誌都會持續存在,直到交易提交或回滾。當語句添加到交易中時,可能會在連續的追蹤器資料值中設定其他標誌。但是,在交易結束之前,不會清除任何標誌。
交易狀態報告為包含一系列 ASCII 字元的字串。每個活動狀態都有一個唯一的字元分配給它,以及在序列中的固定位置。以下列表描述了序列的第 1 到第 8 個位置允許的值
-
位置 1:是否正在進行活動交易。
T
:正在進行明確啟動的交易。I
:正在進行隱式啟動的交易(autocommit=0
)。_
:沒有活動交易。
-
位置 2:在目前交易的上下文中是否讀取了非交易表。
r
:已讀取一個或多個非交易表。_
:到目前為止,尚未讀取非交易表。
-
位置 3:在目前交易的上下文中是否讀取了交易表。
R
:已讀取一個或多個交易表。_
:到目前為止,尚未讀取交易表。
-
位置 4:在目前交易的上下文中是否執行了不安全的寫入(寫入非交易表)。
w
:已寫入一個或多個非交易表。_
:到目前為止,尚未寫入非交易表。
-
位置 5:在目前交易的上下文中是否寫入了任何交易表。
W
:已寫入一個或多個交易表。_
:到目前為止,尚未寫入交易表。
-
位置 6:在目前交易的上下文中是否執行了任何不安全的語句。包含不確定性結構(例如
RAND()
或UUID()
)的語句對於基於語句的複製是不安全的。s
:已執行一個或多個不安全的語句。_
:到目前為止,尚未執行不安全的語句。
-
位置 7:在目前交易期間是否已將結果集傳送到客戶端。
S
:已傳送結果集。_
:到目前為止,尚未傳送結果集。
-
位置 8:
LOCK TABLES
語句是否生效。L
:使用LOCK TABLES
明確鎖定表格。_
:LOCK TABLES
在會話中不活動。
考慮一個包含以下語句的會話,包括啟用交易狀態追蹤器的語句
1. SET @@SESSION.session_track_transaction_info='STATE'; 2. START TRANSACTION; 3. SELECT 1; 4. INSERT INTO t1 () VALUES(); 5. INSERT INTO t1 () VALUES(1, RAND()); 6. COMMIT;
啟用交易狀態追蹤後,以下
data
值會從這些語句產生1. ________ 2. T_______ 3. T_____S_ 4. T___W_S_ 5. T___WsS_ 6. ________
-
以下範例顯示如何呼叫 mysql_session_track_get_first()
和 mysql_session_track_get_next()
,以檢索和顯示成功執行 SQL 語句字串(由 stmt_str
表示)後的所有可用會話狀態變更資訊。假設應用程式已設定啟用其希望接收的通知的 session_track_
系統變數。xxx
printf("Execute: %s\n", stmt_str);
if (mysql_query(mysql, stmt_str) != 0)
{
fprintf(stderr, "Error %u: %s\n",
mysql_errno(mysql), mysql_error(mysql));
return;
}
MYSQL_RES *result = mysql_store_result(mysql);
if (result) /* there is a result set to fetch */
{
/* ... process rows here ... */
printf("Number of rows returned: %lu\n",
(unsigned long) mysql_num_rows(result));
mysql_free_result(result);
}
else /* there is no result set */
{
if (mysql_field_count(mysql) == 0)
{
printf("Number of rows affected: %lu\n",
(unsigned long) mysql_affected_rows(mysql));
}
else /* an error occurred */
{
fprintf(stderr, "Error %u: %s\n",
mysql_errno(mysql), mysql_error(mysql));
}
}
/* extract any available session state-change information */
enum enum_session_state_type type;
for (type = SESSION_TRACK_BEGIN; type <= SESSION_TRACK_END; type++)
{
const char *data;
size_t length;
if (mysql_session_track_get_first(mysql, type, &data, &length) == 0)
{
/* print info type and initial data */
printf("Type=%d:\n", type);
printf("mysql_session_track_get_first(): length=%d; data=%*.*s\n",
(int) length, (int) length, (int) length, data);
/* check for more data */
while (mysql_session_track_get_next(mysql, type, &data, &length) == 0)
{
printf("mysql_session_track_get_next(): length=%d; data=%*.*s\n",
(int) length, (int) length, (int) length, data);
}
}
}