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. ________
-
以下示例显示如何在成功执行 SQL 语句字符串(由 stmt_str
表示)后调用 mysql_session_track_get_first()
和 mysql_session_track_get_next()
来检索并显示所有可用的会话状态更改信息。假设应用程序已设置 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);
}
}
}