#### 17.2.1.3 确定二进制日志中的安全和不安全语句

[](<>)[](<>)[](<>)

MySQL 复制中语句的“安全性”是指语句及其效果是否可以使用基于语句的格式正确复制。如果该陈述是真的，我们称该陈述为安全的；否则，我们将其称为不安全的。

一般来说，如果一个语句是确定性的，它就是安全的，如果不是，它就是不安全的。然而，某些非确定性函数是*不是*被认为是不安全的（见[非确定性函数不被认为是不安全的](replication-rbr-safe-unsafe.html#replication-rbr-safe-unsafe-not)，在本节后面）。此外，使用浮点数学函数结果的语句（依赖于硬件）总是被认为是不安全的（参见[第 17.5.1.12 节，“复制和浮点值”](replication-features-floatvalues.html)）。

**处理安全和不安全的语句。**根据语句是否被认为是安全的，以及相对于二进制日志记录格式（即，当前值[`binlog_format`](replication-options-binary-log.html#sysvar_binlog_format)）。

-   使用基于行的日志记录时，对安全和不安全语句的处理没有区别。

-   使用混合格式日志记录时，标记为不安全的语句使用基于行的格式进行记录；被视为安全的语句使用基于语句的格式记录。

-   使用基于语句的日志记录时，标记为不安全的语句会为此生成警告。安全语句正常记录。

    每个标记为不安全的语句都会生成一个警告。如果在源上执行了大量此类语句，则可能导致错误日志文件过大。为了防止这种情况，MySQL 有一个警告抑制机制。每当最近的 50[`ER_BINLOG_UNSAFE_STATEMENT`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_statement)在任何 50 秒内已生成超过 50 次警告，则启用警告抑制。激活后，这会导致此类警告不写入错误日志；相反，对于这种类型的每 50 个警告，一个注释`上次警告重复 *`ñ`* 上次的次数 *`小号`* 秒`写入错误日志。只要最近 50 个此类警告在 50 秒或更短时间内发出，这种情况就会持续；一旦速率降至此阈值以下，警告将再次正常记录。警告抑制对如何确定基于语句的日志记录的语句安全性没有影响，也对如何向客户端发送警告没有影响。MySQL 客户端仍然会为每个这样的语句收到一个警告。

    有关详细信息，请参阅[第 17.2.1 节，“复制格式”](replication-formats.html).

**被认为不安全的语句。** [](<>)具有以下特征的语句被认为是不安全的：

-   **包含可能在副本上返回不同值的系统函数的语句。**这些功能包括[`FOUND_ROWS()`](information-functions.html#function_found-rows), [`GET_LOCK()`](locking-functions.html#function_get-lock), [`IS_FREE_LOCK()`](locking-functions.html#function_is-free-lock), [`IS_USED_LOCK()`](locking-functions.html#function_is-used-lock), [`加载文件（）`](string-functions.html#function_load-file), [`MASTER_POS_WAIT()`](miscellaneous-functions.html#function_master-pos-wait), [`兰德（）`](mathematical-functions.html#function_rand), [`RELEASE_LOCK()`](locking-functions.html#function_release-lock), [`ROW_COUNT()`](information-functions.html#function_row-count), [`SESSION_USER()`](information-functions.html#function_session-user), [`睡觉（）`](miscellaneous-functions.html#function_sleep), [`SOURCE_POS_WAIT()`](miscellaneous-functions.html#function_source-pos-wait), [`系统日期（）`](date-and-time-functions.html#function_sysdate), [`SYSTEM_USER()`](information-functions.html#function_system-user), [`用户（）`](information-functions.html#function_user), [`UUID()`](miscellaneous-functions.html#function_uuid)， 和[`UUID_SHORT()`](miscellaneous-functions.html#function_uuid-short).

    [](<>)**非确定性函数不被认为是不安全的。**尽管这些函数不是确定性的，但出于日志记录和复制的目的，它们被视为安全的：[`CONNECTION_ID()`](information-functions.html#function_connection-id), [`CURDATE()`](date-and-time-functions.html#function_curdate), [`当前的日期（）`](date-and-time-functions.html#function_current-date), [`当前时间（）`](date-and-time-functions.html#function_current-time), [`CURRENT_TIMESTAMP()`](date-and-time-functions.html#function_current-timestamp), [`时间（）`](date-and-time-functions.html#function_curtime),,[`LAST_INSERT_ID()`](information-functions.html#function_last-insert-id),[`当地时间（）`](date-and-time-functions.html#function_localtime),[`本地时间戳（）`](date-and-time-functions.html#function_localtimestamp),[`现在（）`](date-and-time-functions.html#function_now),[`UNIX_TIMESTAMP()`](date-and-time-functions.html#function_unix-timestamp),[`UTC_DATE()`](date-and-time-functions.html#function_utc-date),[`UTC_TIME()`](date-and-time-functions.html#function_utc-time)， 和[`UTC_TIMESTAMP()`](date-and-time-functions.html#function_utc-timestamp).

    有关详细信息，请参阅[第 17.5.1.14 节，“复制和系统功能”](replication-features-functions.html).

-   **对系统变量的引用。**大多数系统变量没有使用基于语句的格式正确复制。看[第 17.5.1.39 节，“复制和变量”](replication-features-variables.html).有关例外情况，请参阅[第 5.4.4.3 节，“混合二进制日志记录格式”](binary-log-mixed.html).

-   **可加载函数。**由于我们无法控制可加载函数的功能，因此必须假设它正在执行不安全的语句。

-   **全文插件。**这个插件在不同的MySQL服务器上可能会有不同的行为；因此，依赖于它的语句可能会产生不同的结果。因此，在MySQL中，所有依赖全文插件的语句都被视为不安全的。

-   **触发器或存储程序更新具有自动\_增量列。**这是不安全的，因为行的更新顺序在源和副本上可能不同。

    此外[`插入`](insert.html)放入具有包含`自动增量`不是此复合键的第一列的列不安全。

    有关更多信息，请参阅[第17.5.1.1节，“复制和自动\_增量“](replication-features-auto-increment.html).

-   **插入对具有多个主键或唯一键的表执行重复键更新语句。**当对包含多个主键或唯一键的表执行此语句时，该语句被认为是不安全的，它对存储引擎检查键的顺序很敏感，这是不确定的，MySQL服务器更新的行的选择取决于该顺序。

    一[`插入关于重复密钥更新`](insert-on-duplicate.html)对于基于语句的复制，针对具有多个唯一键或主键的表的语句被标记为不安全。（臭虫11765650，臭虫58637）

-   **使用限制更新。**没有指定检索行的顺序，因此被认为是不安全的。看见[第17.5.1.18节“复制和限制”](replication-features-limit.html).

-   **访问或引用日志表。**源和副本之间的系统日志表的内容可能不同。

-   **事务性操作之后的非事务性操作。**在事务中，允许在任何事务性读写之后执行任何非事务性读写被认为是不安全的。

    有关更多信息，请参阅[第17.5.1.35节，“复制和交易”](replication-features-transactions.html).

-   **访问或引用自日志记录表。**对自记录表的所有读写都被认为是不安全的。在事务中，对自日志记录表进行读或写操作之后的任何语句也被认为是不安全的。

-   **加载数据语句。**  [`加载数据`](load-data.html)被视为不安全，何时[`binlog_格式=混合`](replication-options-binary-log.html#sysvar_binlog_format)该语句以基于行的格式记录。什么时候[`binlog_format=语句`](replication-options-binary-log.html#sysvar_binlog_format) [`加载数据`](load-data.html)与其他不安全声明不同，不会生成警告。

-   **XA事务。**如果在源上并行提交的两个XA事务正在副本上以相反的顺序准备，则基于语句的复制可能会出现无法安全解决的锁定依赖项，并且复制可能会因副本上的死锁而失败。什么时候[`binlog_format=语句`](replication-options-binary-log.html#sysvar_binlog_format)设置时，XA事务中的DML语句被标记为不安全，并生成警告。什么时候[`binlog_格式=混合`](replication-options-binary-log.html#sysvar_binlog_format)或[`binlog_格式=行`](replication-options-binary-log.html#sysvar_binlog_format)设置后，XA事务中的DML语句将使用基于行的复制进行记录，并且不存在潜在问题。

-   **`违约`指不确定函数的子句。**如果表达式默认值引用的是不确定函数，则任何导致表达式求值的语句对于基于语句的复制都是不安全的。这包括以下声明：[`插入`](insert.html), [`使现代化`](update.html)和[`改变桌子`](alter-table.html)。与大多数其他不安全语句不同，此类语句无法以基于行的格式安全复制。什么时候[`binlog_格式`](replication-options-binary-log.html#sysvar_binlog_format)即将`陈述`，则会记录并执行该语句，但会在错误日志中写入警告消息。什么时候[`binlog_格式`](replication-options-binary-log.html#sysvar_binlog_format)即将`混合的`或`一行`，则不会执行该语句，并将错误消息写入错误日志。有关显式默认值处理的更多信息，请参阅[从MySQL 8.0.13开始的显式默认处理](data-type-defaults.html#data-type-defaults-explicit).

    有关更多信息，请参阅[第17.5.1节，“复制功能和问题”](replication-features.html).
