下面,主要是验证在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格式下,则不仅会复制触发条件,还会复制触发动作。

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

MySQL主从环境下存储过程,函数,触发器,事件的复制情况的更多相关文章

  1. 监控Mysql主从环境下Slave延迟状态的操作记录

    在MySQL主从环境下,通常会根据Seconds_Behind_Master的值来判断slave的延迟状态,这么做在大部分情况下尚可接受,但其实是并不够准确的.对于Slave延迟状态的监控,应该考虑多 ...

  2. redis持久化策略梳理及主从环境下的策略调整记录

    redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化.可以不定期的通过异步方式保存到磁盘上(即“半持久化模式”):也可以把每一次数据变化都写入到一个A ...

  3. 查看SQL SERVER 加密存储过程,函数,触发器,视图

    原文:查看SQL SERVER 加密存储过程,函数,触发器,视图 create  PROCEDURE sp_decrypt(@objectname varchar(50))ASbeginset noc ...

  4. mysql主从模式下在主库上的某些操作不记录日志的方法

    mysql主从模式下在主库上的某些操作不记录日志的方法 需求场景: 在主库上的需要删除某个用户,而这个用户在从库上不存在(我在接手一个业务的时候,就遇到主从架构用户授权不一致的情况,主库比较全,而从库 ...

  5. mysql 控制台环境下查询中文数据乱码,插入、更新中文数据不成功

    mysql 控制台环境下查询中文数据乱码,插入.更新中文数据不成功         登录mysql密码是加入编码参数--default-character-set,中文用gbk mysql -uroo ...

  6. 用 Docker 构建 MySQL 主从环境

    开源Linux 一个执着于技术的公众号 前言 本篇文章记录使用 docker-compose 以及 dockerfile 来构建基于 binlog 的 MySQL 主从环境.如果你严格按照文中的步骤进 ...

  7. linux环境下验证码不显示的几种情况

    linux环境下验证码不显示的几种情况 gd库扩展没有安装. 查看phpinfo(),看看有没有安装gd库 yum安装gd库或者phpize安装 安装完成后记得重启php-fpm bom头的原因 在生 ...

  8. 如何在ES5与ES6环境下处理函数默认参数

    函数默认值是一个很提高鲁棒性的东西(就是让程序更健壮)MDN关于函数默认参数的描述:函数默认参数允许在没有值或undefined被传入时使用默认形参. ES5 使用逻辑或||来实现 众所周知,在ES5 ...

  9. mysql主从同步下---主从配置

    1.安装mysql主从服务器   1.1 初始化docker中mysql挂载目录 # 新建2个目录, 存放master和slave的配置和数据, cd ~ # ~ 代表家目录 /home/你的用户名/ ...

随机推荐

  1. 试试SQLSERVER2014的内存优化表

    试试SQLSERVER2014的内存优化表 SQL Server 2014中的内存引擎(代号为Hekaton)将OLTP提升到了新的高度. 现在,存储引擎已整合进当前的数据库管理系统,而使用先进内存技 ...

  2. 用scikit-learn进行LDA降维

    在线性判别分析LDA原理总结中,我们对LDA降维的原理做了总结,这里我们就对scikit-learn中LDA的降维使用做一个总结. 1. 对scikit-learn中LDA类概述 在scikit-le ...

  3. 【每日一linux命令3】参数(或称选项)顺序

    一般除了特殊情况,参数是没有顺序的.举例而言,输入"–a –v"与输入"–v –a"以及"–av" 的执行效果是相同的.但若该参数后指定了要 ...

  4. 谈谈一些有趣的CSS题目(九)-- 巧妙的实现 CSS 斜线

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  5. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之目录导航

    ASP.NET MVC with Entity Framework and CSS是2016年出版的一本比较新的.关于ASP.NET MVC.EF以及CSS技术的图书,我将尝试着翻译本书以供日后查阅. ...

  6. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(一)

    初识马尔可夫和马尔可夫链 作者:白宁超 2016年7月10日20:34:20 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学习自然语言处 ...

  7. mount报错: you must specify the filesystem type

    在linux mount /dev/vdb 到 /home 分区时报错: # mount /dev/vdb /homemount: you must specify the filesystem ty ...

  8. Visual Studio Code——Angular2 Hello World 之 2.0

    最近看到一篇用Visual Studio Code开发Angular2的文章,也是一篇入门教程,地址为:使用Visual Studio Code開發Angular 2專案.这里按部就班的做了一遍,感觉 ...

  9. 【iOS10 SpeechRecognition】语音识别 现说现译的最佳实践

    首先想强调一下“语音识别”四个字字面意义上的需求:用户说话然后马上把用户说的话转成文字显示!,这才是开发者真正需要的功能. 做需求之前其实是先谷歌百度一下看有没有造好的轮子直接用,结果真的很呵呵,都是 ...

  10. iOS9支付宝无法调起客户端

    1.为了适配 iOS9.0 中的 App Transport Security(ATS)对 http 的限制,这里需要对 支付宝的请求地址 alipay.com 做例外,在 app 对应的 info. ...