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;
)。可以使用
SET TRANSACTION
(不帶任何GLOBAL
或SESSION
關鍵字),或使用僅適用於下一個交易的語法設定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);
}
}
}