在 MySQL 复制中,语句的“安全性”是指该语句及其效果是否可以使用基于语句的格式正确复制。如果语句满足此条件,则称该语句为安全;否则,称该语句为不安全。
一般来说,如果语句是确定性的,则该语句是安全的;如果语句不是确定性的,则该语句是不安全的。但是,某些非确定性函数不被视为不安全(请参阅本节后面的不被视为不安全的非确定性函数)。此外,使用浮点数学函数结果的语句(这些函数是硬件相关的)始终被视为不安全(请参阅第 19.5.1.12 节,“复制和浮点数”)。
安全和不安全语句的处理。 语句的处理方式取决于该语句是否被视为安全,以及二进制日志格式(即binlog_format
的当前值)。
使用基于行的日志记录时,不会区分安全和不安全语句的处理方式。
使用混合格式日志记录时,标记为不安全的语句将使用基于行的格式进行日志记录;被认为安全的语句将使用基于语句的格式进行日志记录。
使用基于语句的日志记录时,标记为不安全的语句会生成一条警告信息。安全语句会正常记录。
每个标记为不安全的语句都会生成一条警告信息。如果在源上执行了大量此类语句,这会导致错误日志文件过大。为了防止这种情况,MySQL 提供了警告抑制机制。每当在任何 50 秒的时间段内生成超过 50 次的 50 个最新的ER_BINLOG_UNSAFE_STATEMENT
警告时,就会启用警告抑制。启用此功能后,这些警告不会写入错误日志;相反,每 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.40 节,“复制和变量”。有关例外情况,请参见 第 7.4.4.3 节,“混合二进制日志记录格式”。
可加载函数。 由于我们无法控制可加载函数的行为,因此必须假设它正在执行不安全的语句。
全文插件。 此插件在不同的 MySQL 服务器上的行为可能不同;因此,依赖于它的语句可能会有不同的结果。出于这个原因,所有依赖于全文插件的语句在 MySQL 中都被视为不安全的。
触发器或存储过程更新具有 AUTO_INCREMENT 列的表。 这是不安全的,因为行更新的顺序在源和副本上可能不同。
此外,
INSERT
到具有包含非第一列的AUTO_INCREMENT
列的复合主键的表中是不安全的。有关更多信息,请参见 第 19.5.1.1 节,“复制和 AUTO_INCREMENT”。
在具有多个主键或唯一键的表上使用 INSERT ... ON DUPLICATE KEY UPDATE 语句。 当针对包含多个主键或唯一键的表执行此语句时,此语句被认为是不安全的,因为它对存储引擎检查键的顺序很敏感,该顺序不是确定性的,并且 MySQL 服务器选择更新的行取决于该顺序。
针对具有多个唯一键或主键的表的
INSERT ... ON DUPLICATE KEY UPDATE
语句对于基于语句的复制被标记为不安全。 (错误 #11765650,错误 #58637)使用 LIMIT 的更新。 行检索的顺序未指定,因此被认为是不安全的。请参见 第 19.5.1.19 节,“复制和 LIMIT”。
访问或引用日志表。 系统日志表的内容在源和副本之间可能不同。
在事务操作之后进行非事务操作。 在事务中,允许任何非事务读取或写入在任何事务读取或写入之后执行被认为是不安全的。
有关更多信息,请参见 第 19.5.1.36 节,“复制和事务”。
访问或引用自记录表。 对自记录表的所有读取和写入都被认为是不安全的。在事务中,任何在读取或写入自记录表之后执行的语句也被认为是不安全的。
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 节,“复制功能和问题”。