5.5 Mysql 服务器插件

参考官方文档:

https://dev.mysql.com/doc/refman/5.7/en/server-plugins.html

MySQL支持一个可以创建服务器组件的插件API。 可以在服务器启动时加载插件,或者在运行时加载和卸载插件,而无需重新启动服务器。 此接口支持的组件包括但不限于存储引擎,INFORMATION_SCHEMA表,全文分析器插件,分区支持和服务器扩展。

MySQL发行版包含几个实现服务器扩展的插件:

  • 用于验证客户端连接到MySQL服务器的尝试的插件。 插件可用于多种认证协议。
  • 一个连接控制插件,使管理员能够在一定数量的连续失败的客户端连接尝试后引入延时。
  • 密码验证插件实现密码强度策略并评估潜在密码的强度。
  • 通过组复制,您可以跨一组MySQL服务器实例创建高度可用的分布式MySQL服务,并且数据一致性,冲突检测和解决以及组内成员服务都是内置的。
  • MySQL企业版包含一个线程池插件,通过高效地管理大量客户端连接的语句执行线程来管理连接线程,从而提高服务器性能。
  • MySQL企业版包含一个审计插件,用于监视和记录连接和查询活动
  • MySQL企业版包括一个防火墙插件,它实现了一个应用程序级别的防火墙,使数据库管理员可以允许或拒绝执行基于与已接受语句模式的白名单进行匹配的SQL语句执行
  • 查询重写插件检查MySQL服务器收到的语句,并可能在服务器执行它们之前重写它们。
  • 版本令牌允许创建应用程序可以使用的服务器令牌并对其进行同步,以防止访问不正确或过时的数据。 版本令牌基于一个插件库,该库实现了version_tokens插件和一组用户定义的函数。
  • X插件扩展了MySQL服务器以能够作为文档存储。 运行X插件可使MySQL服务器使用X协议与客户端通信,该协议旨在将MySQL的ACID兼容存储功能作为文档存储。
  • 半同步复制插件实现复制功能的接口,只要至少有一个从站响应每个事务,就允许主站继续进行。
  • 测试框架插件测试服务器服务。

以下各节介绍如何安装和卸载插件,以及如何在运行时确定安装哪些插件并获取有关插件的信息

5.5.1 安装和卸载插件

服务器插件必须先加载到服务器才能使用。 MySQL在服务器启动和运行时支持插件加载。 也可以在启动时控制加载插件的激活状态,并在运行时卸载它们。

加载插件时,有关它的信息在运行时可以从INFORMATION_SCHEMA.PLUGINS表和SHOW PLUGINS语句获得。

安装插件

在使用服务器插件之前,必须使用以下方法之一安装服务器插件。 在说明中,plugin_name代表插件名称,例如innodb,csv或validate_password。

Built-in plugins:

服务器会自动识别内置的插件。 通常,服务器在启动时启用该插件。 一些内置的插件允许用–plugin_name [= activation_state]选项来改变它。

在mysql.plugin系统表中注册的插件:

mysql.plugin表充当插件的注册表(除了内置插件,不需要注册)。 启动时,服务器加载表中列出的每个插件。 通常,对于从mysql.plugin表中加载的插件,服务器还会启用该插件。 这可以通过–plugin_name [= activation_state]选项进行更改。

如果服务器使用–skip-grant-tables选项启动,则不会查询mysql.plugin表,也不会加载列出的插件。

使用命令行选项命名的插件:

位于插件库文件中的插件可以在服务器启动时加载–plugin-load,–plugin-load-add或(从MySQL 5.7.11开始) – 初始插件加载选项。 通常,对于启动时加载的插件,服务器还会启用该插件。 这可以通过–plugin_name [= activation_state]选项进行更改。

在插件和存储引擎已经在服务器启动序列期间初始化之后,–plugin-load和–plugin-load-add选项加载插件。 –early-plugin-load选项用于加载在内置插件和存储引擎初始化之前必须可用的插件。

每个插件加载选项的值都是以name=plugin_library和plugin_library值的分号分隔的列表。 每个名称都是要加载的插件的名称,而plugin_library是包含插件代码的库文件的名称。 如果插件库的名称没有任何前面的插件名称,则服务器会加载库中的所有插件。 服务器在由plugin_dir系统变量命名的目录中查找插件库文件。

插件加载选项不会在mysql.plugin表中注册任何插件。 对于后续重新启动,仅当再次给出–plugin-load,–plugin-load-add或–early-plugin-load时,服务器才会再次加载插件。 也就是说,该选项会生成一次性插件安装操作,该操作会持续进行单个服务器调用。

–plugin-load,–plugin-load-add和–early-plugin-load使得即使在给出–skip-grant-tables的情况下也可以加载插件(这会导致服务器忽略mysql.plugin表)。 –plugin-load,–plugin-load-add和–early-plugin-load也允许在运行时无法加载的插件在启动时加载。

–plugin-load-add选项补充了–plugin-load选项:

  • –plugin-load的每个实例都会重新设置启动时加载的插件集合,而–plugin-load-add将插件或插件添加到要加载的插件集合,而不会重置当前集合。 因此,如果指定了多个–plugin-load实例,则只有最后一个生效。 使用多个–plugin-load-add实例,它们全部生效。
  • 参数格式与–plugin-load相同,但可以使用多个–plugin-load-add实例来避免将大量插件指定为单个冗长的不易使用的插件加载参数。
  • –plugin的负载加可以在缺少-plugin负荷的情况下给出,但是–plugin负荷相加之前出现的任何实例–plugin负荷不起作用,因为–plugin负荷会重 置加载一组插件。

例如:这些选项:

–plugin-load=x –plugin-load-add=y

等价于这些选项:

–plugin-load=”x;y”

但是这些选项:

–plugin-load-add=y –plugin-load=x

等价于这些选项

–plugin-load=x

使用INSTALL PLUGIN语句安装的插件:

位于插件库文件中的插件可以在运行时用INSTALL PLUGIN语句加载。 该语句还将插件注册到mysql.plugin表中,以使服务器在后续重新启动时加载它。 因此,INSTALL PLUGIN需要mysql.plugin表的INSERT权限。

插件库文件的基本名称取决于您的平台。 对于Unix和类Unix系统,常见后缀是.so,对于Windows,则为.dll。

示例:–plugin-load选项在服务器启动时安装一个插件。 要从名为somepluglib.so的插件库文件安装名为myplugin的插件,请在my.cnf文件中使用以下行:

[mysqld]

plugin-load=myplugin=somepluglib.so

在这种情况下,该插件未在mysql.plugin中注册。 不使用–plugin-load选项重新启动服务器会导致插件在启动时不加载。

或者,INSTALL PLUGIN语句会导致服务器在运行时从库文件加载插件代码:

INSTALL PLUGIN myplugin SONAME ‘somepluglib.so’;

INSTALL PLUGIN也会导致“永久”插件注册:该插件列在mysql.plugin表中,以确保服务器在后续重新启动时加载它。

许多插件可以在服务器启动时或运行时加载。 但是,如果插件的设计必须在服务器启动期间加载并初始化,则尝试在运行时使用INSTALL PLUGIN加载它会产生错误:

mysql> INSTALL PLUGIN myplugin SONAME ‘somepluglib.so’; ERROR 1721 (HY000): Plugin ‘myplugin’ is marked as not dynamically installable. You have to stop the server to install it.

在这种情况下,您必须使用–plugin-load,–plugin-load-add或–early-plugin-load。

如果插件在mysql.plugin表中使用–plugin-load,–plugin-load-add或–early-plugin-load选项和(作为更早的INSTALL PLUGIN语句的结果)命名, 服务器启动但将这些消息写入错误日志:

[ERROR] Function ‘plugin_name‘ already exists [Warning] Couldn’t load plugin named ‘plugin_name‘ with soname ‘plugin_object_file‘.

控制插件活动状态

如果服务器在启动时知道插件(例如,因为插件使用–plugin-load选项进行了命名或在mysql.plugin表中注册),则服务器默认加载并启用该插件。 使用–plugin_name [= activation_state]启动选项可以控制此插件的激活状态,其中plugin_name是要影响的插件的名称,例如innodb,csv或validate_password。 与其他选项一样,破折号和下划线在选项名称中可以互换。 另外,激活状态值不区分大小写。 例如,–my_plugin = ON和–my-plugin = on是等效的。

  • plugin_name=OFF

通知服务器禁用该插件。 这可能不适用于某些内置插件,如mysql_native_password。

  • plugin_name[=ON]

通知服务器启用该插件。 (将选项指定为不带值的–plugin_name具有相同的效果。)如果插件无法初始化,则服务器在禁用插件的情况下运行。

  • plugin_name=FORCE

告诉服务器启用插件,但是如果插件初始化失败,服务器不会启动。 换句话说,这个选项强制服务器在插件启用下运行,或则不运行。

  • plugin_name=FORCE_PLUS_PERMANENT

像FORCE一样,但是另外防止插件在运行时被卸载。 如果用户尝试使用UNINSTALL PLUGIN执行此操作,则会发生错误。

插件激活状态在INFORMATION_SCHEMA.PLUGINS表的LOAD_OPTION列中可见。

假设CSV,BLACKHOLE和ARCHIVE是内置的可插拔存储引擎,并且希望服务器在启动时加载它们,但要符合以下条件:如果CSV初始化失败,则必须允许服务器运行,要求BLACKHOLE必须初始化成功, 并应该禁用ARCHIVE。 要做到这一点,请在选项文件中使用这些行:

[mysqld]

csv=ON

blackhole=FORCE

archive=OFF

–enable-plugin_name选项格式是–plugin_name = ON的同义词。 –disable-plugin_name和–skip-plugin_name选项格式是–plugin_name = OFF的同义词。

如果某个插件被禁用,显式使用OFF或隐式使用,因为它已启用但未初始化,则需要该插件的服务器操作方面将发生变化。 例如,如果插件实现存储引擎,则存储引擎的现有表变得不可访问,并且尝试为存储引擎创建新表会生成使用默认存储引擎的表,除非启用了NO_ENGINE_SUBSTITUTION SQL模式在发生这种情况时引起一个错误。

禁用插件可能需要对其他选项进行调整。 例如,如果使用–skip-innodb启动服务器以禁用InnoDB,则启动时可能需要省略其他innodb_xxx选项。 另外,因为InnoDB是默认的存储引擎,所以,除非您使用–default_storage_engine指定另一个可用的存储引擎 ,其不会启动。 您还必须设置–default_tmp_storage_engine。

卸载插件

在运行时,UNINSTALL PLUGIN语句禁用并卸载服务器已知的插件。 该语句将卸载该插件,并将其从mysql.plugin表中删除,如果它在其中注册的话。 因此,UNINSTALL PLUGIN语句需要mysql.plugin表的DELETE权限。 如果插件不再注册在表中,服务器在后续重新启动不会自动加载插件。

UNINSTALL PLUGIN可以卸载一个插件,无论它是在运行时用INSTALL PLUGIN加载的还是在启动时用插件加载选项加载的,受到以下条件的限制:

  • 它无法卸载内置于服务器的插件。 这些可以被识别为来自INFORMATION_SCHEMA.PLUGINS或SHOW PLUGINS的输出中库名为NULL的那些。
  • 它无法卸载 由–plugin_name = FORCE_PLUS_PERMANENT启动服务器的插件 ,这会阻止插件在运行时卸载。 这些可以从INFORMATION_SCHEMA.PLUGINS表的LOAD_OPTION列中识别。

要卸载当前在服务器启动时加载的插件,请使用此过程。

  1. 从my.cnf文件中删除与该插件相关的任何选项。
  2. 重启服务器
  3. 插件通常使用启动时的插件加载选项或运行时的INSTALL PLUGIN安装,但不能同时使用。 但是,如果在某个时候INSTALL PLUGIN也被使用了,从my.cnf文件中删除插件的选项可能不足以将其卸载。 如果该插件仍然出现在INFORMATION_SCHEMA.PLUGINS或SHOW PLUGINS的输出中,请使用UNINSTALL PLUGIN将其从mysql.plugin表中删除。 然后重新启动服务器。

5.5.2 获取服务器插件信息

有几种方法可以确定服务器中安装了哪些插件:

  • INFORMATION_SCHEMA.PLUGINS表为每个加载的插件包含一行。 任何有PLUGIN_LIBRARY值为NULL的为内置的,并且不能被卸载。

mysql> SELECT * FROM information_schema.PLUGINS\G

  • SHOW PLUGINS语句为每个加载的插件显示一行。 任何具有NULL值的库都是内置的,无法卸载。

mysql> SHOW PLUGINS\G

  • mysql.plugin表显示哪些插件已用INSTALL PLUGIN注册。 该表仅包含插件名称和库文件名,所以它不提供像PLUGINS表或SHOW PLUGINS语句那样多的信息。

5.5.4 查询重写插件

从MySQL 5.7.6开始,MySQL服务器支持查询重写插件,可以在服务器执行它们之前检查并可能修改服务器接收的语句。

MySQL发行版包括一个名为Rewriter的Postparse查询重写插件和用于安装插件及其相关组件的脚本。 这些组件共同提供SELECT重写功能:

  • 名为Rewriter的服务器端插件会检查SELECT语句,并可能会根据其重写规则的内存缓存重写它们。 准备好的语句中的独立SELECT语句和SELECT语句可能会被重写。 在视图定义或存储程序中发生的SELECT语句不会被重写。
  • 重写器插件使用名为query_rewrite的数据库,其中包含一个名为rewrite_rules的表。 该表提供了插件用于决定是否重写语句的规则的持久存储。 用户通过修改该表中存储的规则集与插件进行通信。 该插件通过设置表行的message列来与用户进行通信。
  • query_rewrite数据库包含一个名为flush_rewrite_rules()的存储过程,它将规则表的内容加载到插件中。
  • flush_rewrite_rules()存储过程使用名为load_rewrite_rules()的用户定义函数。
  • 重写器插件公开了启用插件配置和状态变量以提供运行时操作信息的系统变量。

以下各节介绍如何安装和使用重写器插件,并为其关联组件提供参考信息。

5.5.4.1 安装和卸载 重写查询插件

注意:

如果安装了,重写器插件即使在禁用时也会涉及一些开销。 为了避免这种开销,除非你打算使用它,否则不要安装插件。

要安装或卸载重写器查询重写插件,请选择位于MySQL安装的共享目录中的approropriate脚本:

  • install_rewriter.sql:选择此脚本来安装重写器插件及其相关组件。
  • 在MySQL 5.7.8之前,有两个安装脚本install_rewriter.sql和install_rewriter_with_optional_columns.sql,它们是否创建rewrite_rules表的pattern_digest和normalized_columns列是不同的。 从5.7.8开始,安装脚本始终创建这些列。
  • uninstall_rewriter.sql:选择此脚本来卸载重写器插件及其相关组件。

按如下所示运行所选脚本:

shell> mysql -u root -p < install_rewriter.sql

Enter password: (enter root password here)

这里的示例使用install_rewriter.sql安装脚本。 如果您选择不同的脚本,请进行适当的替换。

运行安装脚本会安装并启用插件。 要验证,请连接到服务器并执行以下语句:

SHOW GLOBAL VARIABLES LIKE ‘rewriter_enabled’;

5.5.4.2 使用查询重写插件

要启用或禁用插件,请启用或禁用rewriter_enabled系统变量。 默认情况下,重写器插件在安装时启用。 要明确设置初始插件状态,可以在服务器启动时设置变量。 例如,要在选项文件中启用插件,请使用以下行:

[mysqld]

rewriter_enabled=ON

也可以在运行时启用或禁用插件:

mysql> SET GLOBAL rewriter_enabled = ON;

mysql> SET GLOBAL rewriter_enabled = OFF;

假设重写器插件已启用,它将检查并可能修改服务器接收的每个SELECT语句。 该插件根据重写规则的内存缓存确定是否重写语句,该规则是从query_rewrite数据库的rewrite_rules表中加载的。

增加重写规则

要为 Rewriter 插件添加规则,请将行添加到rewrite_rules表中,然后调用flush_rewrite_rules()存储过程以将表中的规则加载到插件中。 以下示例创建一个简单的规则来匹配选择单个文字值的语句:

mysql> INSERT INTO query_rewrite.rewrite_rules (pattern, replacement) VALUES(‘SELECT ?’, ‘SELECT ? + 1’);

生成的表内容如下所示:

mysql> SELECT * FROM query_rewrite.rewrite_rules\G

该规则指定一个模式模板,指示要匹配哪些SELECT语句以及指示如何重写匹配语句的替换模板。 但是,将规则添加到rewrite_rules表中并不足以导致重写器插件使用该规则。 您必须调用flush_rewrite_rules()将表内容加载到插件内存中缓存中:

mysql> CALL query_rewrite.flush_rewrite_rules()

tip:

如果您的重写规则似乎不能正常工作,请确保您已通过调用flush_rewrite_rules()重新加载规则表。

当插件从规则表中读取每条规则时,它会根据模式和 digest 散列值计算标准化(语句 digest )形式,并使用它们更新normalized_pattern和pattern_digest列:

mysql> SELECT * FROM query_rewrite.rewrite_rules\G

模式使用与预处理语句相同的语法。 在模式模板中,? 字符充当与数据值匹配的参数标记。 参数标记只能用于出现数据值的地方,而不能用于SQL关键字,标识符等等。 这个? 字符不应包含在引号内。

像模式一样,replacement 可以包含?字符。 对于匹配模式模板的语句,插件会重写它,replacement ? 参数标记在替换中使用与模式中相应标记匹配的数据值。 结果是一个完整的语句字符串。 插件会要求服务器解析它,并将结果作为重写语句的表示返回给服务器。

添加并加载规则后,根据语句是否符合规则模式,检查是否发生重写:

mysql> SELECT PI();

mysql> SELECT 10;

+——–+ | 10 + 1 |

+——–+ | 11 | +——–+

1 row in set, 1 warning (0.00 sec)

第一个SELECT语句没有重写,但是第二个是。 第二条语句说明了当插件重写一条语句时,它会产生一条警告消息。 要查看消息,请使用SHOW WARNINGS:

mysql> SHOW WARNINGS\G *************************** 1. row ***************************

Level: Note Code: 1105 Message: Query ‘SELECT 10’ rewritten to ‘SELECT 10 + 1’ by a query rewrite plugin

要启用或禁用现有规则,请修改其 enabled 列并将表重新加载到插件中。 要禁用规则1:

mysql> UPDATE query_rewrite.rewrite_rules SET enabled = ‘NO’ WHERE id = 1;

mysql> CALL query_rewrite.flush_rewrite_rules();

这使您可以在不从表格中删除规则的情况下取消规则活动。

重新启用规则1:

mysql> UPDATE query_rewrite.rewrite_rules SET enabled = ‘YES’ WHERE id = 1;

mysql> CALL query_rewrite.flush_rewrite_rules();

rewrite_rules表包含一个pattern_database列,Rewriter使用该列来匹配不符合数据库名称限定的表名:

  • 如果相应的数据库和表名称相同,则语句中的表名与模式中的限定名匹配。

  • 只有当默认数据库与pattern_database相同且表名称相同时,语句中的非限定表名才与模式中的非限定名匹配

–表名是否使用前缀限定数据库的情况

假设一个名为appdb.users的表有一个名为id的列,并且应用程序需要使用一个查询从表中选择行,其中第二个只能在appdb是默认数据库时使用:

SELECT * FROM users WHERE appdb.id = id_value;

SELECT * FROM users WHERE id = id_value;

还假设id列被重命名为user_id(也许该表必须被修改为添加另一种类型的ID并且需要更具体地指示id列所代表的什么类型的ID)。

更改意味着应用程序必须在WHERE子句中引用user_id而不是id。 但是,如果有旧的应用程序无法写入来更改它们生成的SELECT查询,则它们将不再正常工作。 重写器插件可以解决这个问题。 要匹配和重写语句,无论它们是否符合表名,请添加以下两条规则并重新加载规则表:

mysql> INSERT INTO query_rewrite.rewrite_rules -> (pattern, replacement) VALUES( -> ‘SELECT * FROM appdb.users WHERE id = ?’, -> ‘SELECT * FROM appdb.users WHERE user_id = ?’ -> );

mysql> INSERT INTO query_rewrite.rewrite_rules -> (pattern, replacement, pattern_database) VALUES( -> ‘SELECT * FROM users WHERE id = ?’, -> ‘SELECT * FROM users WHERE user_id = ?’, -> ‘appdb’ -> );

mysql> CALL query_rewrite.flush_rewrite_rules();

–也就数说,字段变更,代码不用变更,但其实往往变更都是由应用发起,在这里略显鸡肋。

重写器使用第一条规则来匹配使用限定表名的语句。 它使用第二个匹配使用非限定名称的语句,但仅当默认数据库是appdb(pattern_database中的值)时才使用该语句。

语句匹配如何工作

重写器插件使用语句摘要和摘要散列值来分阶段地将传入语句与重写规则进行匹配。 max_digest_length系统变量确定用于计算语句摘要的缓冲区的大小。 较大的值可用于计算区分较长语句的摘要。 较小的值使用较少的内存,但增加了较长的语句与相同摘要值碰撞的可能性。

该插件将每条语句与重写规则进行匹配,如下所示:

  1. 计算语句摘要哈希值并将其与规则摘要哈希值进行比较。 这受制于误报,但可作为快速拒绝测试。
  2. 如果语句摘要哈希值与任何模式摘要哈希值匹配,则将语句的规范化(语句摘要)形式与匹配规则模式的规范化形式进行匹配。
  3. 如果规范化语句与规则匹配,则比较语句和模式中的文字值。 ? 在模式中匹配语句中的任何文字值。 如果语句准备SELECT语句,在语句中 ? 在模式中也匹配? 。 否则,相应的文字必须相同。

如果多条规则匹配一条语句,则不确定插件使用哪一条语句来重写语句。

如果一个 pattern 包含比 replacement 更多的标记,则该插件会丢弃多余的数据值。 如果一个 pattern 包含的标记数量少于替换的标记数量,则这是一个错误 。当规则表被加载时,插件会注意到这一点,将错误消息写入规则行的 message 列来传达问题,并将Rewriter_reload_error状态变量设置为ON。

重写被准备的语句

准备好的语句在解析时(即准备时)被重写,而不是稍后执行。

准备好的语句与非准备语句的区别在于它们可能包含? 字符作为参数标记。 匹配一个? 在准备好的声明中,重写器模式必须包含? 在相同的位置。 假设重写规则有这种模式:

SELECT ?, 3

下表显示了几个准备好的SELECT语句以及规则模式是否匹配它们。

Prepared StatementWhether Pattern Matches StatementPREPARE s AS ‘SELECT 3, 3’YesPREPARE s AS ‘SELECT ?, 3’YesPREPARE s AS ‘SELECT 3, ?’NoPREPARE s AS ‘SELECT ?, ?’No

重写器插件操作信息

重写器插件通过几个状态变量提供有关其操作的信息:

mysql> SHOW GLOBAL STATUS LIKE ‘Rewriter%’;

| Variable_name | Value | +———————————–+——-+ | Rewriter_number_loaded_rules | 1 | | Rewriter_number_reloads | 5 | | Rewriter_number_rewritten_queries | 1 | | Rewriter_reload_error | ON | +———————————–+—–

当通过调用flush_rewrite_rules()存储过程加载规则表时,如果某些规则发生错误,则CALL语句会产生错误,并且插件将Rewriter_reload_error状态变量设置为ON:

mysql> CALL query_rewrite.flush_rewrite_rules(); ERROR 1644 (45000): Loading of some rule(s) failed.

mysql> SHOW GLOBAL STATUS LIKE ‘Rewriter_reload_error’;

+———————–+——-+

| Variable_name | Value |

+———————–+——-+

| Rewriter_reload_error | ON |

当通过调用flush_rewrite_rules()存储过程加载规则表时,如果某些规则发生错误,则CALL语句会产生错误,并且插件将Rewriter_reload_error状态变量设置为ON:

重写器插件使用的字符集

当rewrite_rules表被加载到重写器插件中时,插件使用character_set_client系统变量的当前全局值来解释语句。 如果全局character_set_client值随后发生更改,则必须重新加载规则表。

客户端必须具有与加载规则表时,与全局值相同的会话character_set_client值,否则规则匹配将不适用于该客户端。

5.5.4.3 查询重写插件参考

以下讨论可作为与重写器查询重写插件相关组件的参考:

  • 重写器规则表在query_rewrite数据库中
  • Rewriter 存储过程和函数
  • Rewriter 系统和状态变量

5.5.4.3.1 查询重写插件表

query_rewrite数据库中的rewrite_rules表为重写器插件用于决定是否重写语句的规则提供持久存储。

用户通过修改该表中存储的规则集与插件进行通信。 该插件通过设置表的message列与用户进行通信。

注意:

规则表由flush_rewrite_rules存储过程加载到插件中。 除非在最近的表修改之后调用该过程,否则表内容不一定对应于插件正在使用的一组规则。

rewrite_rules表具有以下列:

  • id

规则ID。 该列是表主键。 您可以使用该ID来唯一标识任何规则。

  • patten

指示规则匹配的语句模式的模板。 使用 ? 以表示与数据值匹配的参数标记。

  • pattern_database

用于匹配语句中不合格表名的数据库。 如果相应的数据库和表名称相同,则语句中的合格表名与模式中的限定名匹配。 只有当默认数据库与pattern_database相同且表名相同时,语句中的非限定表名才与模式中的非限定名匹配。

  • replacement

指示如何重写与模式列值匹配的语句的模板。 使用 ? 以表示与数据值匹配的参数标记。 在重写的语句中,插件替换? 使用与pattern 中的相应标记匹配的数据值进行 replacement 的参数标记。

  • enabled

规则是否启用。 加载操作(通过调用flush_rewrite_rules()存储过程执行)只有当此列为YES(Y是MySQL 5.7.8之前的版本)时,才会将表中的规则加载到Rewriter内存中缓存中。

此列可以在不删除规则的情况下取消激活规则:将列设置为YES以外的值,并将表重新加载到插件中。

  • message

该插件使用此列与用户进行通信。 如果规则表加载到内存中时没有发生错误,插件会将消息列设置为NULL。 非NULL值表示错误,列内容是错误消息。 在这些情况下可能会发生错误:

  • 模式或替换是一个不正确的SQL语句,它会产生语法错误。
  • 更换比模式包含更多? 参数标记。

如果发生加载错误,插件还会将Rewriter_reload_error状态变量设置为ON。

  • pattern_digest

该列用于调试和诊断。 如果规则表加载到内存中时该列存在,插件会使用模式摘要更新它。 如果您试图确定为什么某些语句无法重写,此列可能很有用。

  • normalized_pattern

该列用于调试和诊断。 如果规则表加载到内存中时该列存在,则插件会使用规范化的模式更新它。 如果您试图确定为什么某些语句无法重写,此列可能很有用。

注意:

在MySQL 5.7.8之前,pattern_digest和normalized_pattern列是可选的:如果您使用install_rewriter_with_optional_columns.sql安装Rewriter插件,则会创建它们,但如果使用install_rewriter.sql则不会。

5.5.4.3.2查询重写插件程序和函数

重写器插件操作使用将规则表加载到其内存中缓存的存储过程以及帮助器用户定义的函数(UDF)。 在正常操作下,用户只调用存储过程。 UDF旨在由存储过程调用,而不是由用户直接调用。

  • flush_rewrite_rules()

此存储过程使用load_rewrite_rules()UDF将rewrite_rules表的内容加载到重写器内存中缓存中。 加载表后,它也会清除查询缓存。

调用flush_rewrite_rules()意味着COMMIT。

修改规则表以使插件从新表内容更新其缓存后,调用此过程。 如果发生任何错误,插件将为表中适当的规则行设置消息列,并将Rewriter_reload_error状态变量设置为ON。

  • load_rewrite_rules()

这个UDF是flush_rewrite_rules()存储过程使用的帮助程序。

5.5.4.3.3查询重写插件系统变量

查询重写插件支持以下系统变量。 这些变量只有在插件已安装的情况下才可用

全局变量,布尔型,动态,默认是ON

全局变量,integer,动态,内部使用的参数

5.5.4.3.4 查询重写插件状态变量

已成功从rewrite_rules表加载到内存中供Rewriter插件使用的规则数目。

rewrite_rules表被加载到Rewriter插件使用的内存缓存中的次数。

查询重写插件自加载以来重写的查询数量。

最近一次rewrite_rules表加载到Rewriter插件使用的内存缓存中时是否发生错误。 如果该值为OFF,则不会发生错误。 如果该值为ON,则发生错误; 检查rewriter_rules表的消息列中是否有错误消息。

5.5.5 版本 Tokens

MySQL 5.7.8或更高版本的分发版本包括版本令牌(Version Tokens),该功能可以创建令牌并对其进行同步,这样应用程序可以用来防止访问不正确或过时数据的服务器。

版本令牌接口具有以下特征:

  • 版本令牌是由作为密钥或标识符的名称和值组成的对。
  • 版本令牌可以被锁定。 应用程序可以使用令牌锁来向其他合作应用程序指示令牌正在使用中且不应该被修改。
  • 版本令牌列表是每个服务器建立的; 例如,指定服务器分配或操作状态。 另外,与服务器通信的应用程序可以注册其自己的令牌列表,该令牌列表指示其所需服务器所处的状态。应用程序发送给未处于所需状态的服务器的SQL语句会产生错误。 这是应用程序的一个信号,它应该在所需状态下寻找一个不同的服务器来接收SQL语句。

5.5.5.1 版本 Tokens 组件

版本令牌基于实现这些组件的插件库:

  • 名为version_tokens的服务器端插件保存与服务器关联的版本令牌列表,并订阅针对语句执行事件的通知。 version_tokens插件使用审计插件API来监视来自客户端的传入语句,并将每个客户端的会话特定版本令牌列表与服务器版本令牌列表进行匹配。 如果匹配,插件让语句通过,服务器继续处理它。 否则,插件会向客户端返回错误,并且语句失败。
  • 一组用户定义的函数(UDF)提供了一个SQL级别的API,用于操纵和检查由插件维护的服务器版本令牌列表。 要调用任何版本令牌UDF需要SUPER权限 。
  • 系统变量使客户端能够指定注册所需服务器状态的版本令牌列表。 如果服务器在客户端发送语句时具有不同的状态,则客户端会收到错误。

5.5.5.2 安装和卸载version tokens

注意:

如果安装,版本令牌会涉及一些开销。 为了避免这种开销,除非你打算使用它,否则不要安装它。

本节介绍如何安装或卸载版本令牌,这个在包含插件和用户定义函数的插件库文件中实现。

为了供服务器使用,插件库文件必须位于MySQL插件目录(由plugin_dir系统变量命名的目录)中。 如有必要,请在服务器启动时设置plugin_dir的值,以告知服务器插件目录的位置。

插件库文件基本名称是version_tokens。 每个平台的文件名后缀都不相同(例如,对于Unix和类Unix系是.so,Windows的是.dll)。

要安装版本令牌插件和UDF,请使用INSTALL PLUGIN和CREATE FUNCTION语句(根据需要为您的平台调整.so后缀):

INSTALL PLUGIN version_tokens SONAME ‘version_token.so’;

CREATE FUNCTION version_tokens_set RETURNS STRING SONAME ‘version_token.so’;

CREATE FUNCTION version_tokens_show RETURNS STRING SONAME ‘version_token.so’;

CREATE FUNCTION version_tokens_edit RETURNS STRING SONAME ‘version_token.so’;

CREATE FUNCTION version_tokens_delete RETURNS STRING SONAME ‘version_token.so’;

CREATE FUNCTION version_tokens_lock_shared RETURNS INT SONAME ‘version_token.so’;

CREATE FUNCTION version_tokens_lock_exclusive RETURNS INT SONAME ‘version_token.so’;

CREATE FUNCTION version_tokens_unlock RETURNS INT SONAME ‘version_token.so’;

您必须安装UDF来管理服务器的版本令牌列表,但是您还必须安装该插件,因为没有它,UDF将无法正常工作。

如果插件和UDF在主复制服务器上使用,请将它们安装在所有从属服务器上以避免复制问题。

按照刚刚描述的方式安装后,版本令牌插件和UDF将保持安装状态直到卸载。 要删除它们,请使用UNINSTALL PLUGIN和DROP FUNCTION语句:

UNINSTALL PLUGIN version_tokens;

DROP FUNCTION version_tokens_set;

DROP FUNCTION version_tokens_show;

DROP FUNCTION version_tokens_edit;

DROP FUNCTION version_tokens_delete;

DROP FUNCTION version_tokens_lock_shared;

DROP FUNCTION version_tokens_lock_exclusive;

DROP FUNCTION version_tokens_unlock;

5.5.5.3 使用 version Tokens

Version Tokens可用的场景是访问MySQL服务器集合的系统,但需要通过监视它们并根据负载变化调整服务器分配来进行管理以实现负载平衡。 这样的系统包括这些组件:

  • 要管理的MySQL服务器的集合。
  • 与服务器通信并将其组织成高可用性组的管理或管理应用程序。 组有不同的用途,每个组内的服务器可能有不同的分配。 某个组内的服务器分配可随时更改。
  • 访问服务器以检索和更新数据的客户端应用程序,根据目的分配选择服务器。 例如,客户端不应该将更新发送到只读服务器。

版本令牌允许服务器访问根据分配进行管理,而无需客户端重复查询服务器的分配情况:

  • 管理应用程序执行服务器分配并在每台服务器上建立版本令牌以反映其分配情况。 应用程序缓存这些信息以提供一个中央访问点。

如果某些时候管理应用程序需要更改服务器分配(例如,将其从允许写入更改为只读),则它会更改服务器的版本令牌列表并更新其缓存。

  • 为了提高性能,客户端应用程序从管理应用程序获取缓存信息,从而避免必须检索每个语句的服务器分配信息。 根据它将发布的语句类型(例如读取与写入),客户端会选择一个适当的服务器并连接到它。

—类似于一个中间件管理

  • 另外,客户端向服务器发送它自己的特定于客户端的版本令牌以注册它所需分配的服务器。 对于客户端向服务器发送的每条语句,服务器会将其自己的令牌列表与客户端令牌列表进行比较。 如果服务器令牌列表包含具有相同值的客户端令牌列表中存在的所有令牌,则匹配并且服务器执行该语句。

另一方面,管理应用程序可能已更改了服务器分配及其版本令牌列表。 在这种情况下,新的服务器分配现在可能与客户端要求不兼容。 服务器和客户端令牌列表之间发生令牌不匹配,并且服务器返回错误来回复该语句。 这表示客户端从管理应用程序缓存中刷新版本令牌信息并选择要与之通信的新服务器。

用于检测版本令牌错误和选择新服务器的客户端逻辑可以以不同的方式实现:

  • 客户端可以处理所有的版本令牌注册,不匹配检测以及自身的连接切换。
  • 这些操作的逻辑可以在管理客户端和MySQL服务器之间连接的连接器中实现。 这样的连接器可能会处理不匹配错误检测和重新发送自己的语句,或者它可能会将错误传递给应用程序,并将其留给应用程序重新发送该语句。

以下示例以更具体的形式说明了前面的讨论。

当版本令牌在给定服务器上初始化时,服务器的版本令牌列表为空。 令牌列表维护通过调用用户定义函数(UDF)来执行。 需要SUPER权限才能调用任何版本令牌UDF,因此令牌列表修改预计将由具有该权限的 management 或管理应用程序完成。

假设管理应用程序与客户端查询的一组服务器进行通信,以访问员工和产品数据库(分别命名为emp和prod)。 所有服务器都可以处理数据检索语句,但只有其中一些服务器可以进行数据库更新。 为了在数据库特定的基础上处理这个问题,管理应用程序在每台服务器上建立一个版本令牌列表。 在给定服务器的令牌列表中,令牌名称表示数据库名称,令牌值是read或 write 的,取决于数据库是以只读方式使用还是可读写的。

客户端应用程序通过设置系统变量来注册它们要求服务器匹配的版本令牌列表。 变量设置发生在特定客户端的基础上,因此不同的客户端可以注册不同的需求。 默认情况下,客户端令牌列表为空,与任何服务器令牌列表匹配。 当客户端将其令牌列表设置为非空值时,匹配可能成功或失败,具体取决于服务器版本令牌列表。

要为服务器定义 version token列表,管理应用程序将调用version_token_set()UDF。 (还有用于修改和显示令牌列表的UDF,稍后介绍)。例如,应用程序可能会将这些语句发送一个3个服务器的组:

Server 1:

mysql> SELECT version_tokens_set(’emp=read;prod=read’); +——————————————+ | version_tokens_set(’emp=read;prod=read’) | +——————————————+ | 2 version tokens set. | +——————————————+

Server 2:

mysql> SELECT version_tokens_set(’emp=write;prod=read’); +——————————————-+ | version_tokens_set(’emp=write;prod=read’) | +——————————————-+ | 2 version tokens set. | +——————————————-+

Server 3:

mysql> SELECT version_tokens_set(’emp=read;prod=write’); +——————————————-+ | version_tokens_set(’emp=read;prod=write’) | +——————————————-+ | 2 version tokens set. | +——————————————-+

每种情况下的token列表都被指定为分号分隔的名称=值对列表。 得到的令牌列表值导致这些服务器分配:

  • 任何服务器都接受读取任一数据库。
  • 只有服务器2接受emp数据库的更新。
  • 只有服务器3接受prod数据库的更新。

除了为每个服务器分配版本令牌列表之外,管理应用程序还维护一个反映服务器分配的缓存。

在与服务器通信之前,客户端应用程序会联系管理应用程序并检索有关服务器分配的信息。 然后客户端根据这些分配选择一台服务器。 假设客户端想要在emp数据库上执行读写操作。 根据前面的分配,只有服务器2符合要求。 客户端连接到服务器2并通过设置其version_tokens_session系统变量在那里注册其服务器要求:

mysql> SET @@session.version_tokens_session = ’emp=write’;

对于客户端向服务器2发送的后续语句,服务器会将其自己的版本令牌列表与客户端列表进行比较,以检查它们是否匹配。 如果是这样,语句正常执行:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4981;

Query OK, 1 row affected (0.07 sec) Rows matched: 1 Changed: 1 Warnings: 0

mysql> SELECT last_name, first_name FROM emp.employee WHERE id = 4981;

服务器和客户端版本令牌列表之间的差异可以通过两种方式发生:

  • version_tokens_session值中的令牌名称不存在于服务器令牌列表中。 在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND错误。
  • version_tokens_session值中的令牌值与服务器令牌列表中相应令牌的值不同。 在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_MISMATCH错误。

只要服务器2的分配不变,客户端就会继续使用它进行读取和写入。 但假设管理应用程序想要更改服务器分配,以便emp数据库的写入必须发送到服务器1而不是服务器2.为此,它使用version_tokens_edit()修改两台服务器上的emp令牌值(以及 更新其服务器分配的缓存):

Server 1:

mysql> SELECT version_tokens_edit(’emp=write’); +———————————-+ | version_tokens_edit(’emp=write’) | +———————————-+ | 1 version tokens updated. | +———————————-+

Server 2:

mysql> SELECT version_tokens_edit(’emp=read’); +———————————+ | version_tokens_edit(’emp=read’) | +———————————+ | 1 version tokens updated. | +———————————+

version_tokens_edit()修改服务器令牌列表中的命名令牌,并保持其他令牌不变。

客户端下次向服务器2发送语句时,其自己的令牌列表不再与服务器令牌列表匹配,并且发生错误:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4982; ERROR 3136 (42000): Version token mismatch for emp. Correct value read

在这种情况下,客户端应联系管理应用程序以获取有关服务器分配的更新信息,选择新服务器并将失败的语句发送到新服务器。

注意:

每个客户端必须通过根据向特定服务器注册的令牌列表仅发送语句来配合版本令牌。 例如,如果客户端注册了’emp = read’的令牌列表,则Version Tokens中不会阻止客户端为emp数据库发送更新。 客户端本身必须避免这样做。

–不会禁止写语句,也就是说客户端本身业务还是要划分清楚。

对于从客户端接收到的每个语句,服务器隐式使用锁定,如下所示:

  • 为客户机令牌列表中指定的每个令牌(即version_tokens_session值)使用共享锁
  • 执行服务器和客户端令牌列表之间的比较
  • 根据比较结果执行语句或产生错误
  • 释放锁

服务器使用共享锁,以便可以在不阻塞的情况下进行多个会话的比较,同时防止任何尝试获取排他锁的会话的令牌更改,它会处理服务器令牌列表中相同名称的令牌。

前面的示例仅使用版本令牌插件库中包含的几个用户定义,但还有其他一些。 一组UDF允许对服务器的版本令牌列表进行操作和检查。 另一组UDF允许版本令牌被锁定和解锁。

这些UDF允许创建,更改,删除和检查服务器的版本令牌列表:

  • version_tokens_set()完全替换当前列表并分配一个新列表。 参数是以分号分隔的 name=value 对列表。
  • version_tokens_edit() 能够对当前列表进行部分修改。 它可以添加新的令牌或更改现有令牌的值。 参数是以分号分隔的 name=value对列表。
  • version_tokens_delete() 从当前列表中删除令牌。 该参数是以分号分隔的标记名称列表
  • version_tokens_show() 显示当前令牌列表。 它没有任何争论。

如果成功,每个函数都会返回一个二进制字符串,指示发生了什么操作。 以下示例建立服务器令牌列表,通过添加新令牌来修改它,删除一些令牌并显示结果令牌列表:

mysql> SELECT version_tokens_set(‘tok1=a;tok2=b’); +————————————-+ | version_tokens_set(‘tok1=a;tok2=b’) | +————————————-+

| 2 version tokens set. |

+————————————-+

mysql> SELECT version_tokens_edit(‘tok3=c’); +——————————-+ | version_tokens_edit(‘tok3=c’) | +——————————-+ |

1 version tokens updated.

mysql> SELECT version_tokens_delete(‘tok2;tok1’); +————————————+ | version_tokens_delete(‘tok2;tok1’) | +————————————+ | 2 version tokens deleted. | +————————————+

mysql> SELECT version_tokens_show();

+———————–+ | version_tokens_show() | +———————–+ | tok3=c; | +———————–+

如果令牌列表格式错误,则会发生警告:

mysql> SELECT version_tokens_set(‘tok1=a; =c’); +———————————-+ | version_tokens_set(‘tok1=a; =c’) | +———————————-+ |

1 version tokens set.

| +———————————-+ 1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G *************************** 1. row ***************************

Level: Warning Code: 42000 Message: Invalid version token pair encountered. The list provided is only partially updated. 1 row in set (0.00 sec)

如前所述,版本令牌是使用分号分隔的 name=value 对列表定义的。 考虑调用version_tokens_set():

mysql> SELECT version_tokens_set(‘tok1=b;;; tok2= a = b ; tok1 = 1\’2 3″4’) +—————————————————————+ | version_tokens_set(‘tok1=b;;; tok2= a = b ; tok1 = 1\’2 3″4’) | +—————————————————————+ | 3 version tokens set. | +—————————————————————+

版本令牌解释参数如下:

  • 名称和值周围的空白被忽略。 名称和值中的空格是允许的。 (对于version_tokens_delete(),它接受一个没有值的名字列表,名字周围的空白被忽略。)
  • 没有引用机制
  • 令牌顺序并不重要,只是如果令牌列表包含给定令牌名称的多个实例,则最后一个值优先于先前的值。

根据这些规则,前面的version_tokens_set()调用会生成带有两个令牌的令牌列表:tok1的值为1’2 3″4,tok2的值为a = b。要验证此操作,请调用version_tokens_show():

mysql> SELECT version_tokens_show(); +————————–+

| version_tokens_show() |

+————————–+

| tok2=a = b;tok1=1’2 3″4; |

+————————–+

如果令牌列表包含两个令牌,为什么version_tokens_set()返回3个令牌的值? 这是因为原始记号列表包含tok1的两个定义,而第二个定义替换了第一个。

版本令牌令牌操作UDF将这些约束放置在令牌名称和值上:

  • 令牌名称不能包含=或; 字符并且最大长度为64个字符。
  • 令牌值不能包含;字符。 值的长度受 max_allowed_packet 系统变量的值限制。
  • 版本令牌将令牌名称和值视为二进制字符串,因此比较区分大小写。

版本令牌还包括一组使用令牌锁定和解锁的UDF:

  • version_tokens_lock_exclusive()获取独占版本令牌锁。 它采用一个或多个锁名称和一个超时值的列表。
  • version_tokens_lock_shared()获取共享的版本令牌锁。 它采用一个或多个锁名称和一个超时值的列表。
  • version_tokens_unlock()发布版本令牌锁(独占和共享)。 它没有任何参数。

每个锁定函数返回非零值以获得成功。 否则,会发生错误:

mysql> SELECT version_tokens_lock_shared(‘lock1’, ‘lock2’, 0); +————————————————-+ | version_tokens_lock_shared(‘lock1’, ‘lock2’, 0) | +————————————————-+

| 1 |

+————————————————-+

mysql> SELECT version_tokens_lock_shared(NULL, 0); ERROR 3131 (42000): Incorrect locking service lock name ‘(null)’.

使用版本令牌锁定功能进行锁定是建议性的; 应用程序必须同意合作。

可以锁定不存在的令牌名称。 这不会创建令牌。

注意:

版本令牌锁定功能基于第28.3.1节“锁定服务”中描述的锁定服务,因此对于共享锁和排他锁具有相同的语义。 (版本令牌使用内置于服务器中的锁定服务例程,而不是锁定服务UDF接口,因此无需安装这些UDF即可使用版本令牌。)版本令牌获取的锁使用version_token_locks的锁定服务名称空间。 锁定服务锁可以使用性能模式进行监控,因此版本令牌锁也是如此。

对于版本令牌锁定功能,令牌名称参数完全按照指定使用。 周围的空白不被忽略,=和; 字符是允许的。 这是因为版本令牌只是将令牌名称传递给锁定服务。

5.5.5.4 Version Tokes 参考

version tokens 函数

版本令牌插件库包含多个用户定义的函数。 一组UDF允许对服务器的版本令牌列表进行操作和检查。 另一组UDF允许版本令牌被锁定和解锁。 需要SUPER权限才能调用任何版本令牌UDF。

以下UDF允许创建,更改,删除和检查服务器的版本令牌列表。 解释name_list和token_list参数(包括空格处理)的发生,如第5.5.5.3节“使用版本令牌”中所述,其中提供了有关用于指定令牌的语法的详细信息以及其他示例。

  • version_tokens_delete(name_list)

使用name_list参数从服务器的版本令牌列表中删除令牌,并返回指示操作结果的二进制字符串。 name_list是要删除的版本令牌名称的分号分隔列表。

mysql> SELECT version_tokens_delete(‘tok1;tok3’); +————————————+ | version_tokens_delete(‘tok1;tok3’) | +————————————+ | 2 version tokens deleted. | +————————————+

从MySQL 5.7.9开始,NULL参数被视为一个空字符串,它对令牌列表没有影响。

version_tokens_delete()删除其参数中命名的令牌(如果它们存在)。 (删除不存在的令牌不是错误)要清除令牌列表而不知道列表中的令牌是否包含,请将NULL或不包含令牌的字符串传递给version_tokens_set():

mysql> SELECT version_tokens_set(NULL); +——————————+

| version_tokens_set(NULL) |

+——————————+ | Version tokens list cleared. | +——————————+

mysql> SELECT version_tokens_set(”); +——————————+

| version_tokens_set(”) |

+——————————+ | Version tokens list cleared. | +——————————+

  • version_tokens_edit(token_list)

使用token_list参数修改服务器的版本令牌列表,并返回指示操作结果的二进制字符串。 token_list是以分号分隔的 name=value 对列表,用于指定要定义的每个标记的名称及其值。 如果存在令牌,则使用给定值更新其值。 如果令牌不存在,则使用给定的值创建该令牌。 如果参数为NULL或不包含标记的字符串,则token列表保持不变。

mysql> SELECT version_tokens_set(‘tok1=value1;tok2=value2’); +———————————————–+ | version_tokens_set(‘tok1=value1;tok2=value2’) | +———————————————–+ | 2 version tokens set. | +———————————————–+

mysql> SELECT version_tokens_edit(‘tok2=new_value2;tok3=new_value3’); +——————————————————–+ | version_tokens_edit(‘tok2=new_value2;tok3=new_value3’) | +——————————————————–+ | 2 version tokens updated. | +——————————————————–+

  • version_tokens_set(token_list)

使用token_list参数中定义的标记替换服务器的版本标记列表,并返回一个表示操作结果的二进制字符串。 token_list是以分号分隔的 name=value 对列表,用于指定要定义的每个标记的名称及其值。 如果参数为NULL或不包含令牌的字符串,则清除令牌列表。

mysql> SELECT version_tokens_set(‘tok1=value1;tok2=value2’); +———————————————–+ | version_tokens_set(‘tok1=value1;tok2=value2’) | +———————————————–+ | 2 version tokens set. | +———————————————–+

  • version_tokens_show()

将服务器的版本令牌列表作为包含以分号分隔的 name=value对列表的二进制字符串形式返回。

mysql> SELECT version_tokens_show(); +————————–+

| version_tokens_show() |

+————————–+

| tok2=value2;tok1=value1; |

+————————–+

以下UDF允许版本令牌被锁定和解锁:

  • version_tokens_lock_exclusive(token_name[,token_name] …, timeout)

获取一个或多个版本令牌的独占锁定,由名称指定为字符串,如果在给定的超时值内没有获取到锁定,则超时并返回错误。

mysql> SELECT version_tokens_lock_exclusive(‘lock1’, ‘lock2’, 10);

+—————————————————–+ | version_tokens_lock_exclusive(‘lock1’, ‘lock2’, 10) | +—————————————————–+

| 1 |

+—————————————————–+

该函数在5.7.8中添加了名为vtoken_get_write_locks()的MySQL 5.7.8并重命名为version_tokens_lock_exclusive()。

  • version_tokens_lock_shared(token_name[,token_name] …, timeout)

获取一个或多个版本令牌的共享锁,由名称指定为字符串,如果在给定的超时值内没有获取到锁,则超时并返回错误。

mysql> SELECT version_tokens_lock_shared(‘lock1’, ‘lock2’, 10);

+————————————————–+ | version_tokens_lock_shared(‘lock1’, ‘lock2’, 10) | +————————————————–+

| 1 |

+————————————————–+

该函数在5.7.8中添加了名为vtoken_get_read_locks()的MySQL 5.7.8并重命名为version_tokens_lock_shared()。

  • version_tokens_unlock()

使用version_tokens_lock_exclusive()和version_tokens_lock_shared()释放在当前会话中获取的所有锁定。

mysql> SELECT version_tokens_unlock(); +————————-+

| version_tokens_unlock() |

+————————-+

| 1 |

+————————-+

该函数在5.7.9中添加了名为vtoken_release_locks()的MySQL 5.7.8并重命名为version_tokens_unlock()。

锁定函数具有以下特点:

  • 成功返回值不为零。 否则,会发生错误。
  • 令牌名称是字符串。
  • 与操纵服务器令牌列表的UDF的参数处理相比,令牌名称参数周围的空白不会被忽略,并且=和; 字符是允许的。
  • 可以锁定不存在的令牌名称。 这不会创建令牌。
  • 超时值是非负整数,表示在发生错误超时之前等待获取锁定的时间(以秒为单位)。 如果超时为0,则不会等待,并且如果不能立即获取锁,则函数会产生错误。
  • 版本令牌锁定功能基于第28.3.1节“锁定服务”中介绍的锁定服务。

version Tokens system 变量

版本令牌支持以下系统变量。 除非安装了版本令牌插件,否则这些变量不可用

系统变量:

全局+会话,动态,字符串类型,默认值是null

此变量的会话值指定客户端版本令牌列表,并指示客户端会话要求服务器版本令牌列表具有的令牌。

如果version_tokens_session变量为NULL(默认值)或具有空值,则任何服务器版本令牌列表都匹配。 (实际上,一个空值会禁用匹配需求。)

如果version_tokens_session变量具有非空值,则其值与服务器版本令牌列表之间的任何不匹配都会导致会话发送到服务器的任何语句出错。 在这些条件下发生不匹配:

  • version_tokens_session值中的令牌名称不存在于服务器令牌列表中。 在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND错误。
  • version_tokens_session值中的令牌值与服务器令牌列表中相应令牌的值不同。 在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_MISMATCH错误。

服务器版本令牌列表不包含未在version_tokens_session值中指定的令牌。

假设管理应用程序已经设置了服务器令牌列表,如下所示:

mysql> SELECT version_tokens_set(‘tok1=a;tok2=b;tok3=c’); +——————————————–+ | version_tokens_set(‘tok1=a;tok2=b;tok3=c’) | +——————————————–+ | 3 version tokens set. | +——————————————–+

客户端通过设置version_tokens_session值来注册它需要服务器匹配的令牌。 然后,对于客户端发送的每个后续语句,服务器都会根据客户端version_tokens_session值检查其标记列表,并在出现不匹配时产生错误:

mysql> SET @@session.version_tokens_session = ‘tok1=a;tok2=b’; mysql> SELECT 1;

+—+

| 1 |

+—+

| 1 |

+—+

mysql> SET @@session.version_tokens_session = ‘tok1=b’;

mysql> SELECT 1; ERROR 3136 (42000): Version token mismatch for tok1. Correct value a

第一个SELECT成功,因为客户端令牌tok1和tok2出现在服务器令牌列表中,并且每个令牌在服务器列表中具有相同的值。 第二个SELECT失败,因为虽然tok1存在于服务器令牌列表中,但它具有与客户端指定的值不同的值。

此时,除非服务器令牌列表发生更改以使其再次匹配,否则客户端发送的任何语句都会失败。 假设管理应用程序如下更改服务器令牌列表:

mysql> SELECT version_tokens_edit(‘tok1=b’); +——————————-+ | version_tokens_edit(‘tok1=b’) | +——————————-+ | 1 version tokens updated. | +——————————-+

mysql> SELECT version_tokens_show();

+———————–+

| version_tokens_show() |

+———————–+

| tok3=c;tok1=b;tok2=b; |

+———————–+

现在,客户端version_tokens_session值与服务器令牌列表匹配,并且客户端可以再次成功执行语句:

mysql> SELECT 1;

+—+

| 1 |

+—+

| 1 |

+—+

这个变量在 MYSQL 5.7.8被增加

全局+会话,非动态,整形,默认值为0

这个变量由内部使用,在5.7.8被添加

    原文作者:sybbjs
    原文地址: https://zhuanlan.zhihu.com/p/34483747
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞