警告使用语句写入二进制日志的不安全语句

Posted

技术标签:

【中文标题】警告使用语句写入二进制日志的不安全语句【英文标题】:Warning Unsafe statement written to the binary log using statement 【发布时间】:2016-07-08 08:35:12 【问题描述】:

我已经创建了一个基于触发器的日志系统。 每次插入或更新一行时,触发器都会在另一个表中存储一个新行。

触发器工作正常,但一段时间后我在日志中发现了这条消息:

[Warning] Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly. Statement: update `gl_item` set `is_shown` = '0', `updated_at` = '2016-03-21 16:56:28' where `list_id` = '1' and `is_shown` = '1'

我已经为我喜欢的与此问题相关的一些帖子加红了: - mysql Replication & Triggers

但我不明白问题的本质。

这个警告是什么意思? 我不必使用触发器插入到自动增量列中吗? 为了避免此警告,创建日志系统的最佳方法是什么?

更新SHOW CREATE TABLE 的输出,这是触发器将进入 THE 行的表。

gl_item_log | CREATE TABLE `gl_item_log` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Item log unique id',
  `item_id` bigint(20) unsigned DEFAULT NULL ,
  `updated_by` bigint(20) unsigned DEFAULT NULL ,
  `switch_shown` tinyint(4) DEFAULT NULL ,
  `switch_checked` tinyint(4) DEFAULT NULL ,
  `logged_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `logged_at_microtime` decimal(6,6) unsigned NOT NULL ,
  `logged_at_microtime_int` mediumint(8) unsigned NOT NULL DEFAULT '0' ,
  PRIMARY KEY (`id`),
  KEY `gl_item_log_updated_by_foreign` (`updated_by`),
  KEY `gl_item_log_item_id_updated_by_switch_shown_switch_checked_index` 
      (`item_id`,`updated_by`,`switch_shown`,`switch_checked`),
  CONSTRAINT `gl_item_log_item_id_foreign` 
      FOREIGN KEY (`item_id`) REFERENCES `gl_item` (`id`),
  CONSTRAINT `gl_item_log_updated_by_foreign` 
      FOREIGN KEY (`updated_by`) REFERENCES `gl_general_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

id 列与自动增量字段一起删除以使日志条目没有唯一标识符是个好主意吗?

谢谢

【问题讨论】:

请提供SHOW CREATE TABLE 更新后我的回答仍然有效。快速修复是删除id 列(如果您不需要它)。或者,如果您愿意,请将其更改为不自动递增并自行设置值。 【参考方案1】:

这个警告是什么意思?

According to the MySQL documentation:

调用触发器(或函数)导致更新 AUTO_INCREMENT 列的语句未使用基于语句的复制正确复制。 MySQL 5.7 将此类语句标记为不安全。 (错误号 45677)

使用statement-based replication,在您的主数据库上运行的确切 SQL 也会在您的从属数据库上运行。当您的触发器被触发时,如果它存在于您的每个数据库上,它就会在每个数据库上运行并插入到您的日志中。对于您的数据库保持同步来说,这可能是一个棘手的情况。

我不必插入带触发器的自动增量列?

正确。无需将您自己的值插入到自动增量列中。

为了避免此警告,创建日志系统的最佳方法是什么?

首先,要么在每个数据库上保留触发器并关闭日志表的复制,要么只在主数据库上设置触发器并让复制将日志表插入复制到其他数据库。

要解决此特定警告,请将您的日志表配置为没有自动增量列。然后您的触发器可以插入其中,并且不会导致任何复制警告。

另一个选项是切换到基于行的复制。然后触发器只会在主服务器上自动触发,并且自动增量值将始终复制而不会出现问题。

【讨论】:

以上是关于警告使用语句写入二进制日志的不安全语句的主要内容,如果未能解决你的问题,请参考以下文章

Mysql清理二进制日志的技巧

Mysql清理二进制日志的技巧

Mysql的二进制日志---binlog

MYSQL的binlog日志

通过Binlog恢复数据

MySQL 的 binlog 日志