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 varchar(10),IN age int)
 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_time=0    error_code=0
use `test`/*!*/;
SET TIMESTAMP=1476112718/*!*/;
SET @@session.pseudo_thread_id=2/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`(IN name varchar(10),IN age int)
BEGIN
 insert into test.t1 values(name,age);
END
/*!*/;
DELIMITER ;

 

实践存储过程

mysql> call p1('tom',10);
Query OK, 1 row affected (0.08 sec)

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

 

查看二进制日志被,记录的凡还是call p1(‘tom’,10)操作记录对应之SQL语句

# at 574
#161010 23:23:54 server id 1  end_log_pos 653 CRC32 0xc532cfae     Query    thread_id=2    exec_time=0    error_code=0
SET TIMESTAMP=1476113034/*!*/;
BEGIN
/*!*/;
# at 653
#161010 23:23:54 server id 1  end_log_pos 833 CRC32 0x2982c7a8     Query    thread_id=2    exec_time=0    error_code=0
SET TIMESTAMP=1476113034/*!*/;
insert into test.t1 values( NAME_CONST('name',_utf8'tom' COLLATE 'utf8_general_ci'), NAME_CONST('age',10))
/*!*/;
# at 833
#161010 23:23:54 server id 1  end_log_pos 864 CRC32 0xdf106f41     Xid = 56
COMMIT/*!*/;

有鉴于此,对于仓储过程,在主从复制中,记录的凡储存过程对应之DML操作,而未是调用动作本身。

 

函数

创函数

CREATE FUNCTION f1 (string VARCHAR(5))
RETURNS VARCHAR(20) DETERMINISTIC
RETURN CONCAT('f1',string);

亚上前制日志中的记录如下:

# at 1246
#161010 23:34:01 server id 1  end_log_pos 1480 CRC32 0x3a1eb0a2     Query    thread_id=2    exec_time=0    error_code=0
SET TIMESTAMP=1476113641/*!*/;
CREATE DEFINER=`root`@`localhost` FUNCTION `f1`(string VARCHAR(5)) RETURNS varchar(20) CHARSET utf8
    DETERMINISTIC
RETURN CONCAT('f1',string)
/*!*/;

 

实践函数

当此,其实要分开点儿种植状态,一凡是binlog_format为statement,另一样栽情况吗row

当binlog_format为statement时

mysql> show variables like '%binlog_format%';
+---------------+-----------+
| Variable_name | Value     |
+---------------+-----------+
| binlog_format | STATEMENT |
+---------------+-----------+
1 row in set (0.02 sec)

mysql> insert into t1(name) values(f1('steve'));
Query OK, 1 row affected (0.07 sec)

mysql> select * from t1;
+---------+------+
| name    | age  |
+---------+------+
| tom     |   10 |
| f1steve | NULL |
+---------+------+
2 rows in set (0.00 sec)

翻该语句对应的亚上前制日志中之始末

# at 1480
#161010 23:37:58 server id 1  end_log_pos 1559 CRC32 0xf1f2c4a2     Query    thread_id=2    exec_time=0    error_code=0
SET TIMESTAMP=1476113878/*!*/;
BEGIN
/*!*/;
# at 1559
#161010 23:37:58 server id 1  end_log_pos 1673 CRC32 0x0c9a73c5     Query    thread_id=2    exec_time=0    error_code=0
SET TIMESTAMP=1476113878/*!*/;
insert into t1(name) values(f1('steve'))
/*!*/;
# at 1673
#161010 23:37:58 server id 1  end_log_pos 1704 CRC32 0x45419118     Xid = 67
COMMIT/*!*/;

足见在statement的次上制日志格式下,复制的调用函数这个操作自。

 

当binlog_format为row时

mysql> set session binlog_format='row';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1(name) values(f1('tiger'));
Query OK, 1 row affected (0.03 sec)

对应之老二前行制日志的内容

# at 2139
#161010 23:43:35 server id 1  end_log_pos 2211 CRC32 0x7c74abd9     Query    thread_id=2    exec_time=0    error_code=0
SET TIMESTAMP=1476114215/*!*/;
BEGIN
/*!*/;
# at 2211
#161010 23:43:35 server id 1  end_log_pos 2259 CRC32 0x657ac7ac     Table_map: `test`.`t1` mapped to number 78
# at 2259
#161010 23:43:35 server id 1  end_log_pos 2303 CRC32 0x3f15b37c     Write_rows: table id 78 flags: STMT_END_F
### INSERT INTO `test`.`t1`
### SET
###   @1='f1tiger' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */
###   @2=NULL /* VARSTRING(30) meta=0 nullable=1 is_null=1 */
# at 2303
#161010 23:43:35 server id 1  end_log_pos 2334 CRC32 0xe5acc4aa     Xid = 80
COMMIT/*!*/;

足见,在row格式下,复制的非是函数操作本身,而是函数对应的值。

 

触发器

率先,创建两张测试表

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

创建触发器

delimiter //
CREATE TRIGGER t_test1 BEFORE INSERT ON test1
FOR EACH ROW
BEGIN
INSERT INTO test2 SET a2 = NEW.a1;
END;
//
delimiter ;

老二前行制日志中之笔录如下:

# at 556
#161011 10:46:52 server id 1  end_log_pos 776 CRC32 0xf065830f     Query    thread_id=4    exec_time=0    error_code=0
SET TIMESTAMP=1476154012/*!*/;
CREATE DEFINER=`root`@`localhost` TRIGGER t_test1 BEFORE INSERT ON test1
FOR EACH ROW
BEGIN
INSERT INTO test2 SET a2 = NEW.a1;
END
/*!*/;

 

测试触发器,向test1中上加相同久记下

在STATEMENT格式下

mysql> insert into test1 values(1);
Query OK, 1 row affected (0.07 sec)

mysql> select * from test1;
+------+
| a1   |
+------+
|    1 |
+------+
1 row in set (0.01 sec)

mysql> select * from test2;
+------+
| a2   |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

翻该语句对应之老二上制日志被的内容

# at 776
#161011 10:49:37 server id 1  end_log_pos 855 CRC32 0x0d73131b     Query    thread_id=5    exec_time=0    error_code=0
SET TIMESTAMP=1476154177/*!*/;
BEGIN
/*!*/;
# at 855
#161011 10:49:37 server id 1  end_log_pos 956 CRC32 0x6cf2e73c     Query    thread_id=5    exec_time=0    error_code=0
SET TIMESTAMP=1476154177/*!*/;
insert into test1 values(1)
/*!*/;
# at 956
#161011 10:49:37 server id 1  end_log_pos 987 CRC32 0x98e3a631     Xid = 51
COMMIT/*!*/;

可见,对于触发器,主从均会沾,复制只需要记下点条件本身,在本例中,即“insert
into test1 values(1)”,而无会见记录所引发的点操作,即“INSERT INTO test2
SET a2 = NEW.a1”。

 

在ROW格式下

mysql> set session binlog_format='row';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values(2);
Query OK, 1 row affected (0.06 sec)

对应的亚上前制日志也:

# at 399
#161019 10:10:27 server id 1  end_log_pos 471 CRC32 0x667b6938     Query    thread_id=3    exec_time=0    error_code=0
SET TIMESTAMP=1476843027/*!*/;
BEGIN
/*!*/;
# at 471
#161019 10:10:27 server id 1  end_log_pos 519 CRC32 0xccaee383     Table_map: `test`.`test1` mapped to number 85
# at 519
#161019 10:10:27 server id 1  end_log_pos 567 CRC32 0x9625b60f     Table_map: `test`.`test2` mapped to number 86
# at 567
#161019 10:10:27 server id 1  end_log_pos 607 CRC32 0x620381e3     Write_rows: table id 86
# at 607
#161019 10:10:27 server id 1  end_log_pos 647 CRC32 0xff82eb9d     Write_rows: table id 85 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==
'/*!*/;
### INSERT INTO `test`.`test1`
### SET
###   @1=2 /* INT meta=0 nullable=1 is_null=0 */
# at 647
#161019 10:10:27 server id 1  end_log_pos 678 CRC32 0x5384a1bc     Xid = 87
COMMIT/*!*/;

看得出,在row格式下,会以复制触发操作自己,此时,无论是否去slave上之触发器,主从数据据保持一致。但是在statement的格式下,如果去除了slave上之触发器,则会促成基本数据未一致。

 

EVENT

创建EVENT

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

第二上制日志被之笔录如下:

# at 987
#161011 11:02:45 server id 1  end_log_pos 1218 CRC32 0x875a245e     Query    thread_id=5    exec_time=0    error_code=0
SET TIMESTAMP=1476154965/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
CREATE DEFINER=`root`@`localhost` EVENT e_test1
ON SCHEDULE
EVERY 10 SECOND
DO
INSERT INTO test.test1 VALUES (UNIX_TIMESTAMP())
/*!*/;

 

若是如给EVENT执行,必须以event_scheduler设置为ON,默认为OFF。

mysql> set global event_scheduler=1;
Query OK, 0 rows affected (0.09 sec)

 

这会儿EVENT会执行,每10s向test1表中插入一久记下

mysql> select * from test1;
+------------+
| a1         |
+------------+
|          1 |
| 1476155165 |
| 1476155175 |
+------------+
3 rows in set (0.01 sec)

相应的亚进制日志中之始末

# at 1319
#161011 11:06:05 server id 1  end_log_pos 1398 CRC32 0xcc4e1873     Query    thread_id=7    exec_time=0    error_code=0
SET TIMESTAMP=1476155165/*!*/;
SET @@session.sql_auto_is_null=1/*!*/;
BEGIN
/*!*/;
# at 1398
#161011 11:06:05 server id 1  end_log_pos 1520 CRC32 0x24ee06c6     Query    thread_id=7    exec_time=0    error_code=0
SET TIMESTAMP=1476155165/*!*/;
INSERT INTO test.test1 VALUES (UNIX_TIMESTAMP())
/*!*/;
# at 1520
#161011 11:06:05 server id 1  end_log_pos 1551 CRC32 0xa3ed03fa     Xid = 65
COMMIT/*!*/;

看得出,对于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: 10
      Interval field: SECOND
              Starts: 2016-10-11 11:02:45
                Ends: NULL
              Status: ENABLED
          Originator: 1
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (0.00 sec)

Slave

mysql> show events\G
*************************** 1. row ***************************
                  Db: test
                Name: e_test1
             Definer: root@localhost
           Time zone: SYSTEM
                Type: RECURRING
          Execute at: NULL
      Interval value: 10
      Interval field: SECOND
              Starts: 2016-10-11 11:02:45
                Ends: NULL
              Status: SLAVESIDE_DISABLED
          Originator: 1
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (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格式下,则不但会复制触发条件,还见面复制触发动作。

  1. 于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

 

网站地图xml地图