27.7.6.65 mysql_session_track_get_first()
int mysql_session_track_get_first(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length)
Description
MySQL 实现了会话跟踪器机制,服务器将有关会话状态更改的信息返回给 Client 端。为了控制服务器提供有关状态更改的通知,Client 端应用程序设置名称为session_track_xxx
形式的系统变量,例如session_track_state_change,session_track_schema和session_track_system_variables。参见第 5.1.15 节“Client 端会话状态更改的服务器跟踪”。
更改通知发生在 MySQLClient 端/服务器协议中,该协议在 OK 数据包中包含跟踪器信息,以便可以检测到会话状态更改。为了使 Client 端应用程序能够从 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
:此跟踪器类型 table 示已为一个或多个跟踪的会话系统变量分配了一个值。分配会话系统变量后,每个变量将返回两个值(在单独的调用中)。对于第一次调用,data
是包含变量名称的字符串,length
是字符串长度。对于第二个调用,data
是包含变量值的字符串,而length
是字符串长度。
默认情况下,以下会话系统变量启用通知:
要更改此跟踪器类型的默认通知,请将session_track_schema系统变量设置为以逗号分隔的变量列 table 以跟踪其更改,或将*
设置为跟踪所有变量的更改。要禁用会话变量分配的通知,请将session_track_system_variables设置为空字符串。
SESSION_TRACK_STATE_CHANGE
:此跟踪器类型指示对会话状态的某些跟踪属性进行了更改。data
是包含布尔值标志的字节,该标志指示会话状态是否发生更改。length
应该为 1.该标志 table 示为 ASCII 值,而不是二进制值(例如'1'
而不是0x01
)。
要启用此跟踪器类型的通知,请启用session_track_state_change系统变量。
此跟踪器报告会话状态的以下属性的更改:
-
默认架构(数据库)。
-
系统变量的特定于会话的值。
-
User-defined variables.
-
Temporary tables.
-
Prepared statements.
-
-
SESSION_TRACK_GTIDS
:此跟踪器类型 table 示 GTID 可用。data
包含 GTID 字符串。length
是字符串长度。 GTID 字符串采用标准格式,用于指定一组 GTID 值;参见GTID Sets。
要启用此跟踪器类型的通知,请设置session_track_gtids系统变量。
-
SESSION_TRACK_TRANSACTION_CHARACTERISTICS
:此跟踪器类型指示事务 Feature 可用。data
是包含 Feature 数据的字符串。length
是字符串长度。Feature 跟踪器数据字符串可以为空,或者可以包含一个或多个 SQL 语句,每个语句以分号终止: -
如果没有适用的 Feature,则该字符串为空。会话默认设置适用。 (对于隔离级别和访问方式,这些默认值由transaction_isolation和transaction_read_only系统变量的会话值给出。)
-
如果显式启动了事务,则该字符串包含具有相同 Feature 的重启事务所需的一个或多个语句。通常,这是START TRANSACTION语句(可能使用
READ ONLY
,READ WRITE
和WITH CONSISTENT SNAPSHOT
中的一个或多个)。如果应用了无法传递给START TRANSACTION的任何 Feature(例如ISOLATION LEVEL
),则会在前面加上合适的SET TRANSACTION语句(例如SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; START TRANSACTION READ WRITE;
)。 -
如果未明确启动事务,但是设置了仅适用于下一个事务的一次性 Feature,则会生成一个适合复制该设置的SET TRANSACTION语句(例如
SET TRANSACTION READ ONLY;
)。
-
可以使用SET TRANSACTION而不使用任何GLOBAL
或SESSION
关键字来设置 next-transaction 特性,或者使用仅适用于下一个事务的语法设置transaction_isolation和transaction_read_only系统变量来设置:
SET @@transaction_isolation = value;
SET @@transaction_read_only = value;
有关事务 Feature 作用域级别及其设置方式的更多信息,请参见TransactionFeature 范围。
要启用此跟踪器类型的通知,请将session_track_transaction_info系统变量设置为CHARACTERISTICS
(这也会启用SESSION_TRACK_TRANSACTION_STATE
跟踪器类型)。
事务 Feature 跟踪使 Client 端能够确定如何在另一个会话中重新启动事务,因此它具有与原始会话相同的 Feature。
因为可以在事务开始之前使用SET TRANSACTION来设置 Feature,所以如果没有活动的事务,则 Client 端假定没有事务 Feature 是不安全的。因此,不跟踪事务特性并仅在没有事务处于活动状态时切换连接是不安全的(无论是被事务状态跟踪器还是传统的SERVER_STATUS_IN_TRANS
标志检测到)。如果 Client可能希望在某个时候将其会话切换到另一个连接,则必须订阅 TransactionFeature 跟踪器,并且可以使用 Transaction。
Feature 跟踪器跟踪仅适用于下一个事务的一次性 Feature 的更改。它不跟踪会话变量的更改。因此,Client 端还必须跟踪transaction_isolation和transaction_read_only系统变量,以正确确定在 next-transactionFeature 值为空时适用的会话默认值。 (要跟踪这些变量,请在session_track_system_variables系统变量的值中列出它们。)
SESSION_TRACK_TRANSACTION_STATE
:此跟踪器类型指示事务状态信息可用。data
是包含 ASCII 字符的字符串,每个字符都指示事务状态的某些方面。length
是字符串长度(始终为 8)。
要启用此跟踪器类型的通知,请将session_track_transaction_info系统变量设置为STATE
。
事务状态跟踪使 Client 端能够确定事务是否正在进行中,以及是否可以将其移至其他会话而不回滚。
跟踪器项目的范围是 Transaction。所有状态指示标志将一直保留,直到事务被提交或回滚为止。当将语句添加到事务中时,可以在连续的跟踪器数据值中设置其他标志。但是,在事务结束之前,不会清除任何标志。
Transaction 状态报告为包含 ASCII 字符序列的字符串。每个激活状态都有一个分配给它的唯一字符以及序列中的固定位置。下 table 描述了序列中位置 1 到 8 的允许值:
-
位置 1:是否有正在进行的 Transaction。
-
T
:正在显式启动的事务。-
I
:正在进行隐式启动的事务(autocommit=0)。 -
_
:没有有效的 Transaction。 -
位置 2:是否在当前事务的上下文中读取了非事务 table。
-
-
r
:读取了一个或多个非事务 table。-
_
:到目前为止,未读取任何非事务处理 table。 -
位置 3:是否在当前事务的上下文中读取了事务 table。
-
-
R
:已读取一个或多个事务 table。-
_
:到目前为止尚未读取任何事务 table。 -
位置 4:是否在当前事务的上下文中执行了不安全的写操作(对非事务 table 的写操作)。
-
-
w
:写入了一个或多个非事务处理 table。-
_
:到目前为止,尚未写入任何非事务处理 table。 -
位置 5:是否在当前事务的上下文中写入了任何事务 table。
-
-
W
:已写入一个或多个事务 table。 -
s
:执行了一个或多个不安全的语句。-
_
:到目前为止,尚未执行任何不安全的语句。 -
职位 7:在当前 Transaction 期间是否将结果集发送给 Client。
-
-
S
:已发送结果集。-
_
:到目前为止尚未发送结果集。 -
位置 8:LOCK TABLES语句是否有效。
-
-
L
:table 已使用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. ________
Return Values
零成功。如果发生错误,则为非零值。
Errors
None.
Example
下面的示例显示在成功执行 SQL 语句字符串(由stmt_str
table 示)之后,如何调用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);
}
}
}