某些功能在某些情况下不能很好地复制:
的USER(), CURRENT_USER()(或 CURRENT_USER) UUID(), VERSION()和 LOAD_FILE()功能被复制没有改变,因此并除非基于行的复制功能无法可靠地在从服务器上运行。(请参见 第17.1.2节“复制格式”。)
USER()并 CURRENT_USER()在使用MIXED模式时使用基于行的复制自动复制,并在STATEMENT模式下生成警告。(另请参见 第17.4.1.8节“ CURRENT_USER()的复制”。)对于VERSION() 和也是如此RAND()。
对于NOW(),二进制日志包括时间戳。这意味着在主服务器上对该函数的调用返回的值 将复制到从服务器。为了避免在不同时区的MySQL服务器之间进行复制时出现意外结果,请在主服务器和从服务器上都设置时区。有关更多信息,请参见 第17.4.1.31节“复制和时区”。
为了解释在不同时区的服务器之间进行复制时可能出现的问题,假设主服务器位于纽约,从服务器位于斯德哥尔摩,并且两个服务器都使用本地时间。进一步假设,在主数据库上,创建一个表mytable,对该表 执行一条 INSERT语句,然后从表中进行选择,如下所示:
mysql> CREATE TABLE mytable (mycol TEXT);
Query OK, 0 rows affected (0.06 sec)
mysql> INSERT INTO mytable VALUES ( NOW() );
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM mytable;
±--------------------+
| mycol |
±--------------------+
| 2009-09-01 12:00:00 |
±--------------------+
1 row in set (0.00 sec)
斯德哥尔摩的当地时间比纽约的当地时间晚6个小时;因此,如果您SELECT NOW()在完全相同的时刻在从站上发布,则将2009-09-01 18:00:00返回该值 。因此,如果在复制了刚刚显示mytable的CREATE TABLE和 INSERT语句之后从从服务器的副本中进行 选择,则 可能希望 mycol包含value 2009-09-01 18:00:00。然而,这种情况并非如此; 当您从的从副本中进行选择时mytable,您将获得与主副本 完全相同的结果:
mysql> SELECT * FROM mytable;
±--------------------+
| mycol |
±--------------------+
| 2009-09-01 12:00:00 |
±--------------------+
1 row in set (0.00 sec)
不同于NOW(),该 SYSDATE()函数不是复制安全的,因为它不受SET TIMESTAMP二进制日志中语句的影响,并且如果使用基于语句的日志记录则不确定。如果使用基于行的日志记录,这不是问题。
一种替代方法是使用该 --sysdate-is-now选项使SYSDATE()成为的别名NOW()。必须在主机和从机上完成此操作才能正常工作。在这种情况下,此功能仍会发出警告,但只要–sysdate-is-now在主站和从站上都使用该警告,就可以安全地将其忽略 。
SYSDATE()使用MIXED模式时,将使用基于行的复制自动复制 ,并在STATEMENT模式下生成警告 。
另请参见第17.4.1.31节“复制和时区”。
以下限制仅适用于基于语句的复制,不适用于基于行的复制。的 GET_LOCK(), RELEASE_LOCK(), IS_FREE_LOCK(),和 IS_USED_LOCK()函数手柄用户级锁,而不从知道在主并发上下文复制。因此,不应将这些函数用于插入主表,因为从站上的内容会有所不同。例如,不要发出诸如这样的语句INSERT INTO mytable VALUES(GET_LOCK(…))。在使用MIXED模式时,将使用基于行的复制功能自动复制这些功能,并在STATEMENT模式下生成警告。
当基于语句的复制生效时,作为上述限制的解决方法,您可以使用以下策略:将有问题的函数结果保存在用户变量中,并在以后的语句中引用该变量。例如,INSERT由于对该UUID()函数的引用,以下单行 是有问题的:
INSERT INTO t VALUES(UUID());
要变通解决此问题,请执行以下操作:
SET @my_uuid = UUID();
INSERT INTO t VALUES(@my_uuid);
之所以重复执行该语句序列,@my_uuid是因为的值 作为该INSERT语句之前的用户变量事件存储在二进制日志中, 并且可以在中使用INSERT。
相同的想法适用于多行插入,但使用起来比较麻烦。对于两行插入,可以执行以下操作:
SET @my_uuid1 = UUID(); @my_uuid2 = UUID();
INSERT INTO t VALUES(@my_uuid1),(@my_uuid2);
但是,如果行数很大或未知,则解决方法将很难或不可行。例如,您不能将以下语句转换为给定的单个用户变量与每一行相关联的语句:
INSERT INTO t2 SELECT UUID(), * FROM t1;
在存储的函数中,RAND() 只要在函数执行期间仅被调用一次,就可以正确复制。(您可以将函数执行时间戳和随机数种子视为隐式输入,它们在主服务器和从属服务器上是相同的。)
该FOUND_ROWS()和 ROW_COUNT()功能使用基于语句的复制不可复制的可靠。一种解决方法是将函数调用的结果存储在用户变量中,然后在INSERT语句中使用它 。例如,如果您希望将结果存储在名为的表中 mytable,通常可以这样进行:
SELECT SQL_CALC_FOUND_ROWS FROM mytable LIMIT 1;
INSERT INTO mytable VALUES( FOUND_ROWS() );
但是,如果要复制mytable,则应使用SELECT … INTO,然后将变量存储在表中,如下所示:
SELECT SQL_CALC_FOUND_ROWS INTO @found_rows FROM mytable LIMIT 1;
INSERT INTO mytable VALUES(@found_rows);
这样,用户变量将作为上下文的一部分进行复制,并正确应用于从站。
在使用MIXED模式时,将使用基于行的复制功能自动复制这些功能,并在STATEMENT模式下生成警告。(缺陷#12092,缺陷#30244)
在MySQL 5.6.15之前,LAST_INSERT_ID()如果在从属服务器上启用了诸如–replicate-ignore-dband的 任何过滤选项,则不能正确复制 的值 --replicate-do-table。(缺陷号17234370,缺陷号69861)




