首页 > 数据库 > > 23.7 存储过程的二进制日志
参考官方文档:
https://dev.mysql.com/doc/refman/5.7/en/stored-programs-logging.html
二进制日志包含有关修改数据库内容的SQL语句的信息。 该信息以描述修改的“事件”的形式存储。 二进制日志有两个重要目的:
但是,如果在语句级别进行日志记录,则存储的程序(存储过程和函数,触发器和事件)存在某些二进制日志记录问题:
通常,当SQL语句级别(基于语句的二进制日志记录)发生二进制日志记录时,会导致此处描述的问题。 如果使用基于行的二进制日志记录,则日志包含由于执行SQL语句而对各个行所做的更改。 执行例程或触发器时,将记录行更改,而不是进行更改的语句。 对于存储过程,这意味着不记录CALL语句。 对于存储的函数,将记录函数内的行更改,而不是函数调用。 对于触发器,将记录触发器所做的行更改。 在slave端,只能看到行更改,而不是存储的程序调用。
混合格式二进制日志记录(binlog_format = MIXED)使用基于语句的二进制日志记录,除了一些基于行的二进制日志记录才能够产生正确结果的情况除外。 对于混合格式,当存储的函数,存储过程,触发器,事件或预准备语句包含对基于语句的二进制日志记录不安全的任何内容时,整个语句将标记为不安全并以行格式记录。 用于创建和删除过程,函数,触发器和事件的语句始终是安全的,并以语句格式记录。
在MySQL中使用存储函数的条件可以总结如下。 这些条件不适用于存储过程或事件调度,除非启用了二进制日志记录,否则它们不适用。
默认情况下,要接受CREATE FUNCTION语句,必须至少明确指定DETERMINISTIC,NO SQL或READS SQL DATA中的一个。 否则会发生错误:
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable
此函数是确定性的(并不会修改数据),因此它是安全的:
CREATE FUNCTION f1(i INT)
RETURNS INT
DETERMINISTIC
READS SQL DATA
BEGIN RETURN i;
END;
此函数使用UUID(),这不是确定性的,因此该函数也不是确定性的并且不安全:
CREATE FUNCTION f2()
RETURNS CHAR(36)
CHARACTER SET utf8 BEGIN RETURN UUID();
END;
这个函数 修改数据,所以其也不安全
CREATE FUNCTION f3(p_id INT)
RETURNS INT
BEGIN
UPDATE t SET modtime = NOW() WHERE id = p_id;
RETURN ROW_COUNT();
END;
评估函数的性质是基于创建者的诚实性。 MySQL不会检查声明为DETERMINISTIC的函数去检查是否没有产生非确定性结果的语句。
mysql> SET GLOBAL log_bin_trust_function_creators = 1;
您还可以在启动服务器时使用--log-bin-trust-function-creators = 1选项设置此变量。
如果未启用二进制日志记录,则log_bin_trust_function_creators不适用。 创建函数不需要SUPER,除非如前所述,函数定义中的DEFINER值需要它。
触发器与存储函数类似,因此前面关于函数的注释也适用于触发器除了:CREATE TRIGGER没有可选的DETERMINISTIC特性,因此假设触发器始终是确定性的。 但是,在某些情况下,这种假设可能无效。 例如,UUID()函数是不确定的(并且不会复制)。 在触发器中使用此类功能时要小心。
触发器可以更新表,因此如果您没有所需的权限,则CREATE TRIGGER会出现类似于存储函数的错误消息。 在从属端,slave使用触发器DEFINER属性来确定哪个用户被认为是触发器的创建者。
无论日志记录模式如何,CREATE和DROP语句都将记录为语句。
下面的内容是基于 语句日志记录的,不是基于行的日志
CREATE FUNCTION f1(a INT) RETURNS INT BEGIN
IF (a < 3)
THEN INSERT INTO t2 VALUES (a);
END IF;
RETURN 0;
END;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
SELECT f1(a) FROM t1;
当SELECT语句执行时,函数f1()被调用三次。 其中两个调用插入一行,MySQL为每个调用记录一个SELECT语句。 也就是说,MySQL将以下语句写入二进制日志:
SELECT f1(1);
SELECT f1(2);
这意味着虽然用户必须具有CREATE ROUTINE权限才能创建一个函数,但用户可以编写一个包含危险语句的函数,该函数仅在从服务器上执行,并由具有完全权限的线程处理。 例如,如果主服务器和从属服务器的服务器ID值分别为1和2,则主服务器上的用户可以创建并调用unsafe函数unsafe_func(),如下所示:
mysql> delimiter //
mysql> CREATE FUNCTION unsafe_func () RETURNS INT
-> BEGIN
-> IF @@server_id=2 THEN dangerous_statement; END IF;
-> RETURN 1;
-> END;
-> //
mysql> delimiter ;
mysql> INSERT INTO t VALUES(unsafe_func());
CREATE FUNCTION和INSERT语句被写入二进制日志,因此从服务器将执行它们。 因为从属SQL线程具有完全权限,所以它将执行危险语句。 因此,函数调用对主服务器和从服务器具有不同的影响,并且不是复制安全的。
为了防止启用二进制日志记录的服务器出现这种危险,除了通常需要的CREATE ROUTINE权限外,存储的函数创建者还必须具有SUPER权限。 同样,要使用ALTER FUNCTION,除了ALTER ROUTINE权限外,还必须具有SUPER权限。 如果没有SUPER权限,将发生错误:
ERROR 1419 (HY000):
You do not have the SUPER privilege and binary logging is enabled
(you *might* want to use the less safe log_bin_trust_function_creators variable)
如果您不希望要求函数创建者具有SUPER权限(例如,如果您的系统上具有CREATE ROUTINE权限的所有用户都是有经验的应用程序开发人员),请将全局log_bin_trust_function_creators系统变量设置为1.您还可以启动服务器时使用--log-bin-trust-function-creators = 1选项设置此变量。 如果未启用二进制日志记录,则log_bin_trust_function_creators不适用。 创建函数不需要SUPER,除非如前所述,函数定义中的DEFINER值需要它。
SET @my_var = value;
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3142496/ ,如需转载,请注明出处,否则将追究法律责任。