MariaDB 10.1.1:RBR 的触发器
有时候用户会提出一些乍一看似乎没有意义的需求。但随后你开始探究,并意识到用户是正确的,你是错误的,而这实际上是一个完全合乎逻辑且有效的用例。
当听到有人请求在基于行的复制(RBR)中让触发器在从库上工作时,我曾有过这样的时刻。真的吗?在 RBR 中,触发器所做的所有更改都作为行事件从主库复制到从库。如果触发器在从库上触发,它们将会把更改执行两次。而且,假设只有在从库上设置了触发器(为什么?),在基于语句的复制中,触发器也会在从库上正常运行,不是吗?
是的,它们会正常运行,但并非总能使用基于语句的复制。如果总是可以使用,RBR 就不会被实现。有许多基于语句的复制无法正确处理的情况。Galera 也需要 RBR。事实证明,那个用户确实只在从库上设置了触发器——主库获取所有更新,而从库维护汇总表,触发器负责保持这些表的最新状态。
这就是为什么 MariaDB 10.1.1 现在可以选择为基于行的事件调用触发器。这由系统变量 slave_run_triggers_for_rbr
控制。这个变量定义为
MariaDB [test]> SELECT * FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE --> VARIABLE_NAME='slave_run_triggers_for_rbr'G *************************** 1. row *************************** VARIABLE_NAME: SLAVE_RUN_TRIGGERS_FOR_RBR SESSION_VALUE: NULL GLOBAL_VALUE: NO GLOBAL_VALUE_ORIGIN: COMPILE-TIME DEFAULT_VALUE: NO VARIABLE_SCOPE: GLOBAL VARIABLE_TYPE: ENUM VARIABLE_COMMENT: Modes for how triggers in row-base replication on slave side will be executed. Legal values are NO (default), YES and LOGGING. NO means that trigger for RBR will not be running on slave. YES and LOGGING means that triggers will be running on slave, if there was not triggers running on the master for the statement. LOGGING also means results of that the executed triggers work will be written to the binlog. NUMERIC_MIN_VALUE: NULL NUMERIC_MAX_VALUE: NULL NUMERIC_BLOCK_SIZE: NULL ENUM_VALUE_LIST: NO,YES,LOGGING READ_ONLY: NO COMMAND_LINE_ARGUMENT: REQUIRED 1 row in set (0.01 sec)
也就是说,它是一个全局变量,可以设置为 YES
、NO
和 LOGGING
。默认值为 NO
。设置为 YES
将自然地使触发器对 RBR 事件运行。设置为 LOGGING
将使触发器运行并且触发器所做的更改将写入二进制日志。此模式可在运行时、命令行或配置文件中更改。
无论哪种方式,当 slave_run_triggers_for_rbr
不为 NO
时,MariaDB 从库将为某些行事件调用特定的触发器
- Update_row_event 将调用一个 UPDATE 触发器
- Delete_row_event 将调用一个 DELETE 触发器
- Write_row_event 有点复杂。它的应用方式(是的,MySQL 也是如此)如下
- 从库尝试插入一行。
- 如果表具有
UNIQUE KEY
约束(或PRIMARY KEY
)并且存在冲突行,则冲突行将被更新,使其所有值与应插入的行一致。 - 但是,如果表还具有
FOREIGN KEY
约束或表中存在其他UNIQUE
键,则旧行将被删除并插入新行。这是两个操作而不是一个,因此速度较慢,但保证旧行消失后不会有引用指向它。
也就是说,Write_row_event 可以调用 INSERT 触发器、DELETE 触发器或 UPDATE 触发器,具体取决于是否存在冲突行、违反了哪个
UNIQUE
约束以及表是否被外键约束引用。如果您认为这太复杂——您是对的,我们将在 10.1.2 中简化它。
在这种设置中,特别是如果进一步复制,这些从库成为其他从库的主库,存在触发器为同一行多次运行的风险。为了检测这种错误,MariaDB 会标记已调用触发器的行事件,并且当这些事件被复制时,它们不会在从库上引起进一步的触发器调用。也就是说,主库不能在相关表上有任何触发器,否则从库上的触发器将不会被调用。