微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

MySQL主从环境下存储过程,函数,触发器,事件的复制情况

下面,主要是验证在MysqL主从复制环境下,存储过程,函数,触发器,事件的复制情况,这些确实会让人混淆。

首先,创建一张测试表

MysqL> create table test.t1(name varchar(10),age int);
Query OK,0 rows affected (0.10 sec)

 

存储过程

创建存储过程

delimiter //
CREATE procedure p1 (IN name IN age )
 BEGIN
 insert into test.t1 values(name,age);
END//
delimiter ;

通过查看二进制日志,可以看到该DDL语句已被记录

# at 120
#161010 23:18:38 server id 1  end_log_pos 339 CRC32 0xae3dcfda     Query    thread_id=2    exec_time0    error_code0
use `test`/*!*/;
SET TIMESTAMP1476112718@@session.pseudo_thread_id2@@session.foreign_key_checks1,@@session.sql_auto_is_null0,1); font-weight: bold">@@session.unique_checks@@session.autocommit1@@session.sql_mode1075838976@@session.auto_increment_increment@@session.auto_increment_offset!\C utf8 *//*@@session.character_set_client33,1); font-weight: bold">@@session.collation_connection@@session.collation_server33@@session.lc_time_names0@@session.collation_database=DEFAULTCREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
END
;
DELIMITER ;

 

执行存储过程

MysqL> call p1('tom',1); font-weight: bold">101 row affected (0.08 sec)

MysqLselect * from t1;
+-------+------+
| name  | age  |
| tom   |   10 1 rows in set (0.01 sec)

 

查看二进制日志中,记录的是还是call p1('tom',10)操作记录对应的sql语句

# at 57454 server id 653 CRC32 0xc532cfae     Query    thread_id1476113034BEGIN
;
# at 653833 CRC32 0x2982c7a8     Query    thread_idvalues( NAME_CONST(name' COLLATE utf8_general_ci'),NAME_CONST(age))
833864 CRC32 0xdf106f41     Xid = 56
COMMIT;

由此可见,对于存储过程,在主从复制中,记录的是存储过程对应的DML操作,而不是调用动作本身。

 

函数

创建函数

FUNCTION f1 (string VARCHAR(5RETURNS 20) DETERMINISTIC
RETURN CONCAT(f1
# at 124634:01 server id 1480 CRC32 0x3a1eb0a2     Query    thread_id1476113641FUNCTION `f1`(string 5)) ) CHARSET utf8
    DETERMINISTIC
',string)
*/;

 

执行函数

在这里,其实要分两种情况,一是binlog_format为statement,另一种情况为row

binlog_format为statement时

MysqL> show variables like %binlog_format%;
-------------+-----------+
| Variable_name | Value     | binlog_format | STATEMENT 1 row 0.02into t1(name) values(f1(steve));
Query OK,1); font-weight: bold">0.07 sec)

MysqL-------+------+
| name    | tom     | f1steve | NULL 2 rows 0.00 sec)

查看该语句对应的二进制日志中的内容

# at 148037:58 server id 1559 CRC32 0xf1f2c4a2     Query    thread_id147611387815591673 CRC32 0x0c9a73c5     Query    thread_id16731704 CRC32 0x45419118     Xid 67
*/;

可见在statement的二进制日志格式下,复制的调用函数这个操作本身。

 

binlog_format为row时

MysqLset session binlog_format=row;
Query OK,1); font-weight: bold">0.00tiger0.03 sec)

对应的二进制日志的内容

# at 213943:35 server id 2211 CRC32 0x7c74abd9     Query    thread_id147611421522112259 CRC32 0x657ac7ac     Table_map: `test`.`t1` mapped to number 78
# at 22592303 CRC32 0x3f15b37c     Write_rows: table id  flags: STMT_END_F
### INSERT INTO `test`.`t1`
### SET
###   @1f1tiger'  VARSTRING(30) Meta=30 nullable=1 is_null=0 @2NULL  VARSTRING(30) Meta=0 nullable=1 is_null=1 23032334 CRC32 0xe5acc4aa     Xid 80
可见,在row格式下,复制的不是函数操作本身,而是函数对应的值。

 

触发器

首先,创建两张测试表

TABLE test1(a1 INT);
TABLE test2(a2 INT);

创建触发器

delimiter TRIGGER t_test1 BEFORE ON test1
FOR EACH ROW
INTO test2 SET a2  NEW.a1;
END
delimiter ;

二进制日志中的记录如下:

# at 556161011 10:46:52 server id 776 CRC32 0xf065830f     Query    thread_id4    exec_time1476154012测试触发器,向test1中添加一条记录

在STATEMENT格式下

MysqLinto test1 values( test1;
----+
| a1   |    1 0.01 test2;
| a2   77649:37 server id 855 CRC32 0x0d73131b     Query    thread_id5    exec_time1476154177855956 CRC32 0x6cf2e73c     Query    thread_id956987 CRC32 0x98e3a631     Xid 51
可见,对于触发器,主从均会触发,复制只需记录触发条件本身,在本例中,即“insert into test1 values(1)”,而不会记录所引发的触发操作,即“INSERT INTO test2 SET a2 = NEW.a1”。

 

在ROW格式下

MysqL0.06 sec)

对应的二进制日志为:

# at 399161019 27 server id 471 CRC32 0x667b6938     Query    thread_id3    exec_time1476843027471519 CRC32 0xccaee383     Table_map: `test`.`test1` mapped 85519567 CRC32 0x9625b60f     Table_map: `test`.`test2` mapped 86567607 CRC32 0x620381e3     Write_rows: 607647 CRC32 0xff82eb9d     Write_rows:  flags: STMT_END_F

binlog 
E9YGWBMBAAAAMAAAAAcCAAAAAFUAAAAAAAEABHRlc3QABXRlc3QxAAEDAAGD467M
E9YGWBMBAAAAMAAAADcCAAAAAFYAAAAAAAEABHRlc3QABXRlc3QyAAEDAAEPtiWW
E9YGWB4BAAAAKAAAAF8CAAAAAFYAAAAAAAAAAgAB//4CAAAA44EDYg==
### INSERT INTO `test`.`test2`
### SET
###   @1=2 /* INT Meta=0 nullable=1 is_null=0 */
E9YGWB4BAAAAKAAAAIcCAAAAAFUAAAAAAAEAAgAB//4CAAAAneuC/w==
;
###  `test`.`test1`
### 2  INT Meta=0 nullable=1 is_null=0 647678 CRC32 0x5384a1bc     Xid 87
可见,在row格式下,会同时复制触发操作本身,此时,无论是否删除slave上的触发器,主从数据仍保持一致。但是在statement的格式下,如果删除了slave上的触发器,则会导致主从数据不一致。

 

EVENT

创建EVENT

CREATE EVENT e_test1
 SCHEDULE
EVERY  SECOND
DO
INTO test.test1 VALUES (UNIX_TIMESTAMP());

二进制日志中的记录如下:

# at 98711:02:45 server id 1218 CRC32 0x875a245e     Query    thread_id1476154965@@session.time_zoneSYstem`root`@`localhost` EVENT e_test1
VALUES (UNIX_TIMESTAMP())
*/;

 

如果要让EVENT执行,必须将event_scheduler设置为ON,认为OFF。

MysqLset global event_scheduler0.09 sec)

 

这时EVENT会执行,每10s向test1表中插入一条记录

MysqL----------+
| a1         |          | 1476155165 1476155175 3 rows 0.01 sec)

对应的二进制日志中的内容

# at 131906:05 server id 1398 CRC32 0xcc4e1873     Query    thread_id7    exec_time147615516513981520 CRC32 0x24ee06c6     Query    thread_id15201551 CRC32 0xa3ed03fa     Xid 65
可见,对于EVENT,只是复制EVENT语句。

 

可能有人会疑问,slave上面是否同样会执行event呢?

经测试证明,即使将slave上event_scheduler开启了,也不会导致slave上event的执行,即使执行了stop slave操作,该event同样不会执行。

通过查看主从上的event状态,可以看出两者的不同

Master

MysqL> show events\G
*************************** 1. row ***************************
                  Db: test
                Name: e_test1
             Definer: root@localhost
           Time zone: SYstem
                Type: RECURRING
          Execute at: NULL
      Interval value: 
      Interval field: SECOND
              Starts: 2016-1011 45
                Ends: 
              Status: ENABLED
          Originator: 
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
0.00 sec)

Slave

MysqL
              Status: SLAVESIDE_disABLED
          Originator: 0.00 sec)

可以看出,相同的event,master上的状态是ENABLED,而slave上的状态确是SLAVESIDE_disABLED。

如果要开启slave上面的event,可通过如下命令开启

alter event test.e_test1 enable;

经测试,直接update MysqL.event没有效果

 

总结

1. 对于存储过程,只是复制存储过程中定义的DML语句。

2. 对于函数,在statement格式下,只是复制函数名,也就是说,函数在主从上同样会被执行。

3. 对于触发器,在statement格式下,复制的只是触发条件,而不会是触发动作。也就是说,触发器在主从上同样会被运行。

    但是在row格式下,则不仅会复制触发条件,还会复制触发动作。

4. 对于event,复制的也只是事件体中的DML语句。

 

参考

1. http://dev.mysql.com/doc/refman/5.7/en/create-procedure.html

2. http://dev.mysql.com/doc/refman/5.7/en/create-trigger.html

3. http://dev.mysql.com/doc/refman/5.7/en/create-event.html

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐