在 MySQL 复制中,语句的“安全性”是指该语句及其效果是否可以使用基于语句的格式正确复制。如果语句满足此条件,则我们称该语句为“安全”;否则,我们称其为“不安全”。
通常,如果语句是确定性的,则该语句是安全的,如果语句是非确定性的,则该语句是不安全的。但是,某些非确定性函数不被认为是不安全的(请参见本节后面的“不被认为是不安全的非确定性函数”)。此外,使用浮点数学函数(这些函数依赖于硬件)结果的语句始终被认为是不安全的(请参见“19.5.1.12 复制和浮点数”)。
处理安全和不安全语句。 语句的处理方式取决于该语句是否被认为是安全的,以及二进制日志格式(即 binlog_format 的当前值)。
使用基于行的日志记录时,不会区分安全和不安全语句的处理方式。
使用混合格式日志记录时,标记为不安全的语句使用基于行的格式记录;被认为是安全的语句使用基于语句的格式记录。
使用基于语句的日志记录时,标记为不安全的语句会生成警告消息。安全语句将正常记录。
每个标记为不安全的语句都会生成一个警告消息。如果在源上执行了大量此类语句,则会导致错误日志文件过大。为了防止这种情况,MySQL 具有警告抑制机制。只要在任何 50 秒内,最近的 50 个 ER_BINLOG_UNSAFE_STATEMENT 警告已生成超过 50 次,就会启用警告抑制。当激活时,这会导致此类警告不写入错误日志;相反,对于每 50 个此类警告,错误日志中会写入一条说明 最后一次警告在过去 。只要最近的 50 个此类警告在 50 秒或更短时间内发出,此过程就会持续下去;一旦该比率降至此阈值以下,这些警告就会再次正常记录。警告抑制不会影响如何确定语句基于语句的日志记录的安全性,也不会影响如何将警告发送到客户端。MySQL 客户端仍然会为每个此类语句收到一个警告消息。N 秒内重复了 S 次
有关详细信息,请参见“19.2.1 复制格式”。
包含可能在副本上返回不同值的系统函数的语句。 这些函数包括
FOUND_ROWS()、GET_LOCK()、IS_FREE_LOCK()、IS_USED_LOCK()、LOAD_FILE()、RAND()、RELEASE_LOCK()、ROW_COUNT()、SESSION_USER()、SLEEP()、SOURCE_POS_WAIT()、SYSDATE()、SYSTEM_USER()、USER()、UUID()和UUID_SHORT()。不被认为不安全的非确定性函数。 尽管这些函数不是确定性的,但它们在日志记录和复制方面被视为安全的:
CONNECTION_ID()、CURDATE()、CURRENT_DATE()、CURRENT_TIME()、CURRENT_TIMESTAMP()、CURTIME()、LAST_INSERT_ID()、LOCALTIME()、LOCALTIMESTAMP()、NOW()、UNIX_TIMESTAMP()、UTC_DATE()、UTC_TIME()和UTC_TIMESTAMP()。有关更多信息,请参见 第 19.5.1.14 节“复制和系统函数”。
对系统变量的引用。 大多数系统变量无法使用基于语句的格式正确复制。请参见 第 19.5.1.39 节“复制和变量”。有关例外情况,请参见 第 7.4.4.3 节“混合二进制日志格式”。
可加载函数。 由于我们无法控制可加载函数执行的操作,因此我们必须假设它正在执行不安全的语句。
全文插件。 此插件在不同的 MySQL 服务器上可能表现不同;因此,依赖于它的语句可能会有不同的结果。因此,在 MySQL 中,所有依赖于全文插件的语句都被视为不安全的。
触发器或存储程序更新具有 AUTO_INCREMENT 列的表。 这是不安全的,因为更新行的顺序在源和副本上可能不同。
此外,在包含不是此复合键第一列的
AUTO_INCREMENT列的复合主键的表中进行INSERT是不安全的。有关更多信息,请参见 第 19.5.1.1 节“复制和 AUTO_INCREMENT”。
在具有多个主键或唯一键的表上执行 INSERT ... ON DUPLICATE KEY UPDATE 语句。 当针对包含多个主键或唯一键的表执行此语句时,该语句被认为是不安全的,因为它对存储引擎检查键的顺序敏感,该顺序不是确定性的,并且 MySQL 服务器的选择更新的行取决于该顺序。
针对具有多个唯一键或主键的表的
INSERT ... ON DUPLICATE KEY UPDATE语句被标记为基于语句的复制的不安全操作。(错误 #11765650,错误 #58637)使用 LIMIT 更新。 检索行的顺序未指定,因此被认为是不安全的。请参见 第 19.5.1.18 节“复制和 LIMIT”。
访问或引用日志表。 系统日志表的内容在源和副本之间可能不同。
在事务操作之后进行非事务操作。 在事务中,允许任何非事务读取或写入在任何事务读取或写入之后执行被认为是不安全的。
有关更多信息,请参见 第 19.5.1.35 节“复制和事务”。
访问或引用自日志记录表。 对自日志记录表的所有读取和写入都被认为是不安全的。在事务中,任何在读取或写入自日志记录表之后执行的语句也被认为是不安全的。
LOAD DATA 语句。
LOAD DATA被视为不安全的,并且当binlog_format=MIXED时,该语句将以基于行的格式记录。当binlog_format=STATEMENT时,LOAD DATA不会生成警告,这与其他不安全语句不同。XA 事务。 如果在源上并行提交的两个 XA 事务以相反的顺序在副本上准备,则可能会出现基于语句的复制无法安全解决的锁定依赖关系,并且复制可能会在副本上死锁而失败。当设置
binlog_format=STATEMENT时,XA 事务中的 DML 语句被标记为不安全,并会生成警告。当设置binlog_format=MIXED或binlog_format=ROW时,XA 事务中的 DML 语句将使用基于行的复制进行记录,并且不会出现潜在问题。引用非确定性函数的 DEFAULT 子句。 如果表达式默认值引用非确定性函数,则会导致表达式求值的任何语句对于基于语句的复制都是不安全的。这包括
INSERT、UPDATE和ALTER TABLE等语句。与大多数其他不安全语句不同,此类语句无法以基于行的格式安全复制。当binlog_format设置为STATEMENT时,该语句将被记录并执行,但一条警告消息将写入错误日志。当binlog_format设置为MIXED或ROW时,该语句将不会执行,并且一条错误消息将写入错误日志。有关显式默认值处理的更多信息,请参见 显式默认值处理。
有关其他信息,请参见 第 19.5.1 节“复制功能和问题”。