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);
}
}
}