首页 > 数据库 >MySQL Variables--slave_exec_mode参数

MySQL Variables--slave_exec_mode参数

时间:2023-03-14 15:45:04浏览次数:41  
标签:repl slave nullable -- exec meta null 节点 ###

基础信息

MySQL提供参数slave_exec_mode来控制主从复制中遇到的数据冲突和错误,有严格模式(STRICT)和冥等模式(IDEMPOTENT)两种选项,默认为严格模式。
在严格模式下,MySQL会严格检查每次需要APPLY的BINLOG和当前节点数据是否匹配,并在下列场景中抛出错误并停止复制:

  • 插入操作,要插入的记录在从节点上存在主键或唯一键冲突。
  • 更新操作,要更新的记录在从节点上不存在和不匹配,严格模式需在所有列上进行全部匹配。
  • 删除操作,要删除的记录在从节点上不存在和不匹配,严格模式需在所有列上进行全部匹配。

参数slave_exec_mode的官网解释:
Controls how a replication thread resolves conflicts and errors during replication. IDEMPOTENT mode
causes suppression of duplicate-key and no-key-found errors; STRICT means no such suppression
takes place.

如果发生主从节点数据不一致触发复制异常,可采用:

  • 通过设置参数sql_slave_skip_counter来跳过复制错误,注意参数sql_slave_skip_counter与GTID复制不兼容。
  • 通过设置参数slave-skip-errors来跳过复制错误,注意参数slave-skip-errors不能动态设置需重启MySQL服务。
  • 通过设置参数slave_exec_mode=IDEMPOTENT来跳过复制。

测试环境

MySQL 版本: 5.7.26-29-log Percona Server (GPL)
将MySQL从节点设置为:slave_exec_mode=IDEMPOTENT
在MySQL主节点准备测试数据:

## 删除测试表1
DROP TABLE IF EXISTS `repl_test1`;

## 创建新测试表1
CREATE TABLE `repl_test1` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `c1` int(11) DEFAULT NULL,
  `c2` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uqi_c1` (`c2`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

## 插入测试数据
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 1,1,1;

## 删除测试表2
DROP TABLE IF EXISTS `repl_test2`;

## 创建新测试表2
CREATE TABLE `repl_test2` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `c2` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

## 插入测试数据
INSERT INTO `repl_test2`(`id`,`c2`)SELECT 1,1;

## 刷新BINLOG日志,方便解析
FLUSH LOGS;

查看BINLOG操作日志:

 mysqlbinlog -vvv mysql-bin.000xxx |egrep '###|COMMIT|BEGIN|SESSION.GTID_NEXT'

场景1

场景:主节点插入数据,从节点上已存在该数据,从节点数据和主节点数据完全相同。

先在从节点执行(制造主从数据差异):

INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
INSERT INTO `repl_test2`(`id`,`c2`)SELECT 2,2;

再在主节点执行:

INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
INSERT INTO `repl_test2`(`id`,`c2`)SELECT 2,2;

复制无异常报错,主从节点数据相同。

主节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:76'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:77'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test2`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:76'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:77'/*!*/;
BEGIN
COMMIT

主节点插入从节点已存在数据,从节点数据和主节点数据完全相同:

  • 如果表中存在唯一索引,从节点会将INSERT操作转换为DELETE操作+INSERT操作,并保证最终主从数据相同。
  • 如果表中不存在唯一索引,从节点上不会执行任何操作,并生成一个空事务,并保证最终主从数据相同。

场景2

场景:主节点插入数据,从节点上已存在该数据,从节点数据和主节点数据仅主键相同,其他列不同。

先在从节点执行(制造主从数据差异):

INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,22,22;
INSERT INTO `repl_test2`(`id`,`c2`)SELECT 2,22;

再在主节点执行:

INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
INSERT INTO `repl_test2`(`id`,`c2`)SELECT 2,2;

复制无异常报错,主从节点数据相同。

主节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:84'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:85'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test2`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:84'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=22 /* INT meta=0 nullable=1 is_null=0 */
###   @3=22 /* INT meta=0 nullable=1 is_null=0 */
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;


/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:85'/*!*/;
BEGIN
### UPDATE `test`.`repl_test2`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=22 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

主节点插入从节点已存在数据,从节点数据和主节点数据仅主键相同,其他列不同:

  • 如果表中存在唯一索引,从节点会将INSERT操作转换为DELETE操作+INSERT操作,并保证最终主从数据相同。
  • 如果表中不存在唯一索引,从节点将INSERT操作转换为UPDATE操作,并保证最终主从数据相同。

场景3

场景:主节点插入数据,从节点上已存在该数据,从节点数据和主节点数据仅主键相同和唯一键相同,其他列不同

先在从节点执行(制造主从数据差异):

INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,22;

再在主节点执行:

INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;

复制无异常报错,主从节点数据相同。

主节点产生BINLOG:

SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:92'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:92'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=22 /* INT meta=0 nullable=1 is_null=0 */
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

主节点插入从节点已存在数据,从节点数据和主节点数据仅主键相同和唯一键相同,其他列不同:

  • 如果表中存在唯一索引,从节点会将INSERT操作转换为DELETE操作+INSERT操作,并保证最终主从数据相同。

场景4

场景:主节点插入数据,从节点上已存在该数据,从节点数据和主节点数据主键和唯一键相互冲突,其他列相同。

在主节点插入数据,模拟更多情况:

## 插入测试数据
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;

先在从节点执行(制造主从数据差异):

UPDATE `repl_test1` SET `c1`=3 WHERE `id`=2;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 3,4,3;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 4,2,4;

主从当前状态数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
|  2 |    2 |    2 |
+----+------+------+
2 rows in set (0.00 sec)

## 从节点数据
mysql>  select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
|  2 |    3 |    2 |
|  3 |    4 |    3 |
|  4 |    2 |    4 |
+----+------+------+
4 rows in set (0.00 sec)

再在主节点执行:

INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 3,3,3;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 4,4,4;

复制无异常报错,主从节点数据在所操作的记录上保持相同。

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
|  2 |    2 |    2 |
|  3 |    3 |    3 |
|  4 |    4 |    4 |
+----+------+------+
4 rows in set (0.00 sec)

## 从节点数据
mysql>  select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
|  2 |    3 |    2 |
|  3 |    3 |    3 |
|  4 |    4 |    4 |
+----+------+------+
4 rows in set (0.00 sec)

注意:从节点上在唯一键上出现数据冲突。

主节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:139'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=3 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=3 /* INT meta=0 nullable=1 is_null=0 */
###   @3=3 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:140'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=4 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=4 /* INT meta=0 nullable=1 is_null=0 */
###   @3=4 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:139'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=3 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=4 /* INT meta=0 nullable=1 is_null=0 */
###   @3=3 /* INT meta=0 nullable=1 is_null=0 */
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=3 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=3 /* INT meta=0 nullable=1 is_null=0 */
###   @3=3 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:140'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=4 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=4 /* INT meta=0 nullable=1 is_null=0 */
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=4 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=4 /* INT meta=0 nullable=1 is_null=0 */
###   @3=4 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

主节点插入数据,从节点上已存在该数据,从节点数据和主节点数据主键和唯一键相互冲突,其他列相同:

  • 如果表中存在唯一索引,从节点会将INSERT操作转换为DELETE操作+INSERT操作,并保证主从节点在所操作的列上相同。

场景5

场景:主节点删除数据,但从节点上的数据与主节点上数据不匹配,主键和唯一键相同,其他列不同

先在从节点执行(制造主从数据差异):

UPDATE `repl_test1` SET `c2`=11 WHERE `id`=1;
UPDATE `repl_test1` SET `c2`=11 WHERE `id`=1;

再在主节点执行:

DELETE FROM `repl_test1` WHERE `id`=1;
DELETE FROM `repl_test2` WHERE `id`=1;

复制无异常报错,主从节点数据相同,数据都被删除。

主节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:99'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=1 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:100'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test2`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:99'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=11 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:100'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test2`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=11 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

主节点删除数据,但从节点上的数据与主节点上数据不匹配,主键和唯一键相同,其他列不同:

  • 无论表上是否有唯一索引键,从节点会将主键来进行删除,保证和主节点有相同主键的记录被删除。

场景6

场景:主节点删除数据,但从节点上的数据与主节点上数据不匹配,主键和唯一键相同,其他列不同

在主节点插入数据,模拟更多情况:

## 插入测试数据
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 3,3,4;

先在从节点执行(制造主从数据差异):

UPDATE `repl_test1` SET `c1`=11,`c2`=11 WHERE `id`=1;
UPDATE `repl_test1` SET `c1`=4,`c2`=22 WHERE `id`=2;
UPDATE `repl_test1` SET `c1`=2,`c2`=33 WHERE `id`=3;
UPDATE `repl_test1` SET `c1`=3,`c2`=22 WHERE `id`=2;

再在主节点执行:

DELETE FROM `repl_test1` WHERE `id`=1;
DELETE FROM `repl_test1` WHERE `id`=2;

复制无异常报错,主从节点数据相同,数据都被删除。

主节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:115'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=1 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:116'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点产生BINLOG:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:115'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=11 /* INT meta=0 nullable=1 is_null=0 */
###   @3=11 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:116'/*!*/;
BEGIN
### DELETE FROM `test`.`repl_test1`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=3 /* INT meta=0 nullable=1 is_null=0 */
###   @3=22 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

主节点删除数据,但从节点上的数据与主节点上数据不匹配,主键相同,唯一键和其他列不同:

  • 从节点会将主键来进行删除,保证和主节点有相同主键的记录被删除。

场景7

场景:主节点删除数据,但从节点上的数据与主节点上数据不匹配,从节点在主键维度没有匹配的记录。

在主节点插入数据,模拟更多情况:

## 插入测试数据
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 3,3,3;

先在从节点执行(制造主从数据差异):

DELETE FROM `repl_test1` WHERE `id` = 1;
DELETE FROM `repl_test2` WHERE `id` = 1;
DELETE FROM `repl_test1` WHERE `id` = 3;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 4,3,4;

此时主从数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
|  2 |    2 |    2 |
|  3 |    3 |    3 |
+----+------+------+
3 rows in set (0.00 sec)

## 从节点数据
mysql>  select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  2 |    2 |    2 |
|  4 |    3 |    4 |
+----+------+------+
2 rows in set (0.00 sec)

再在主节点执行:

DELETE FROM `repl_test1` WHERE `id`=1;
DELETE FROM `repl_test2` WHERE `id`=1;
DELETE FROM `repl_test1` WHERE `id`=3;

复制无异常报错,主从节点数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  2 |    2 |    2 |
+----+------+------+
1 row in set (0.00 sec)

## 从节点数据
mysql>  select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  2 |    2 |    2 |
|  4 |    3 |    4 |
+----+------+------+
2 rows in set (0.00 sec)

主节点删除数据,但从节点上的数据与主节点上数据不匹配,从节点在主键维度没有匹配的记录:

  • 从节点会将主键来进行删除,保证和主节点有相同主键的记录被删除。

场景8

场景:主节点更新数据,但从节点上的数据与主节点上数据不匹配,从节点在主键维度存在匹配的记录,但其他数据列不匹配。

在主节点插入数据,模拟更多情况:

## 插入测试数据
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 3,3,3;

先在从节点执行(制造主从数据差异):

UPDATE `repl_test1` SET `c2`=111 WHERE `id` = 1;
UPDATE `repl_test2` SET `c2`=111 WHERE `id` = 1;
UPDATE `repl_test1` SET `c1`=222,`c2`=222 WHERE `id` = 2;

此时主从数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
|  2 |    2 |    2 |
|  3 |    3 |    3 |
+----+------+------+
3 rows in set (0.00 sec)

## 从节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |  111 |
|  2 |  222 |  222 |
|  3 |    3 |    3 |
+----+------+------+
3 rows in set (0.00 sec)

再在主节点执行:

UPDATE `repl_test1` SET c2=11 WHERE `id`=1;
UPDATE `repl_test2` SET c2=11 WHERE `id`=1;
UPDATE `repl_test1` SET c2=22 WHERE `id`=2;

复制无异常报错,主从节点数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |   11 |
|  2 |    2 |   22 |
|  3 |    3 |    3 |
+----+------+------+
3 rows in set (0.00 sec)

## 从节点数据
mysql>  select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |   11 |
|  2 |    2 |   22 |
|  3 |    3 |    3 |
+----+------+------+
3 rows in set (0.00 sec)

主节点上BINLOG为:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:190'/*!*/;
BEGIN
### UPDATE `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=1 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=11 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:191'/*!*/;
BEGIN
### UPDATE `test`.`repl_test2`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=11 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:192'/*!*/;
BEGIN
### UPDATE `test`.`repl_test1`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=22 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点BINLOG为:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:190'/*!*/;
BEGIN
### UPDATE `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=111 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=11 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:191'/*!*/;
BEGIN
### UPDATE `test`.`repl_test2`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=111 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=11 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:192'/*!*/;
BEGIN
### UPDATE `test`.`repl_test1`
### WHERE
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=222 /* INT meta=0 nullable=1 is_null=0 */
###   @3=222 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=22 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

主节点更新数据,但从节点上的数据与主节点上数据不匹配,从节点在主键维度没有匹配的记录:

  • 在应用主节点传递来的日志时,如果按照主键在从节点上找到对应记录,则直接按照主键来进行更新,保证主从节点在操作记录上数据一致。

场景9

场景:主节点更新数据,但从节点上的数据与主节点上数据不匹配,从节点在主键维度没有匹配的记录。

在主节点插入数据,模拟更多情况:

## 插入测试数据
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 3,3,3;

先在从节点执行(制造主从数据差异):

DELETE FROM `repl_test1` WHERE `id` = 1;
DELETE FROM `repl_test2` WHERE `id` = 1;
DELETE FROM `repl_test1` WHERE `id` = 3;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 4,3,4;

此时主从数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
|  2 |    2 |    2 |
|  3 |    3 |    3 |
+----+------+------+
3 rows in set (0.00 sec)

## 从节点数据
mysql>  select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  2 |    2 |    2 |
|  4 |    3 |    4 |
+----+------+------+
2 rows in set (0.00 sec)

再在主节点执行:

UPDATE `repl_test1` SET c2=111 WHERE `id`=1;
UPDATE `repl_test2` SET c2=111 WHERE `id`=1;
UPDATE `repl_test1` SET c2=333 WHERE `id`=3;

复制无异常报错,主从节点数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |  111 |
|  2 |    2 |    2 |
|  3 |    3 |  333 |
+----+------+------+
3 rows in set (0.00 sec)

## 从节点数据
mysql>  select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  2 |    2 |    2 |
|  4 |    3 |    4 |
+----+------+------+
2 rows in set (0.00 sec)

主节点上BINLOG为:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:168'/*!*/;
BEGIN
### UPDATE `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=1 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=111 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:169'/*!*/;
BEGIN
### UPDATE `test`.`repl_test2`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=111 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:170'/*!*/;
BEGIN
### UPDATE `test`.`repl_test1`
### WHERE
###   @1=3 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=3 /* INT meta=0 nullable=1 is_null=0 */
###   @3=3 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=3 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=3 /* INT meta=0 nullable=1 is_null=0 */
###   @3=333 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点BINLOG为:

SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:168'/*!*/;
BEGIN

COMMIT

SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:169'/*!*/;
BEGIN
COMMIT

SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:170'/*!*/;
BEGIN
COMMIT

主节点更新数据,但从节点上的数据与主节点上数据不匹配,从节点在主键维度没有匹配的记录:

  • 在应用主节点传递来的日志时,如果按照主键在从节点上无法找到对应记录,则跳过更新,并生成空事务的BINLOG日志。

场景10

场景:主节点在一个事务中更新多条记录,但从节点上的数据与主节点上数据不匹配,从节点在主键维度存在部分没有匹配的记录。

先在从节点执行(制造主从数据差异):

DELETE FROM `repl_test1` WHERE `id` = 1;

此时主从数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |    1 |
+----+------+------+
1 row in set (0.00 sec)

## 从节点数据
mysql> select * from `repl_test1`;
Empty set (0.00 sec)

再在主节点执行:

BEGIN;
UPDATE `repl_test1` SET c2=111 WHERE `id`=1;
INSERT INTO `repl_test1`(`id`,`c1`,`c2`)SELECT 2,2,2;
COMMIT;

复制无异常报错,主从节点数据为:

## 主节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  1 |    1 |  111 |
|  2 |    2 |    2 |
+----+------+------+
2 rows in set (0.00 sec)

## 从节点数据
mysql> select * from `repl_test1`;
+----+------+------+
| id | c1   | c2   |
+----+------+------+
|  2 |    2 |    2 |
+----+------+------+
1 row in set (0.00 sec)

主节点上BINLOG为:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:199'/*!*/;
BEGIN
### UPDATE `test`.`repl_test1`
### WHERE
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=1 /* INT meta=0 nullable=1 is_null=0 */
### SET
###   @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=1 /* INT meta=0 nullable=1 is_null=0 */
###   @3=111 /* INT meta=0 nullable=1 is_null=0 */
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

从节点上BINLOG为:

/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'c1387dd9-be50-11ed-844c-5cb9019a75d6:199'/*!*/;
BEGIN
### INSERT INTO `test`.`repl_test1`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
###   @3=2 /* INT meta=0 nullable=1 is_null=0 */
COMMIT/*!*/;

标签:repl,slave,nullable,--,exec,meta,null,节点,###
From: https://www.cnblogs.com/gaogao67/p/17215154.html

相关文章

  • E. FTL
    E.FTL代码/*首先如果两个人不能同时使用的话,也就是直接采用地推就可以了然后考虑两个人一起使用枚举一个用了j次,并且他们最后一次是同时进行使用的然后进行地推就可......
  • 《拖延症心理学》-郭婷 精华选取
    说明:针对新书,通常会先看目录,看完目录再去浅读文章,发现已经将所有精华都已提取出来了,文章只是举例说明。想看此书,个人观点觉得看目录即可: 第一章 做人不逃避,做事不拖......
  • 写多读少
    数据库写入请求量过大,导致系统出现性能与可用性问题常见的方式就是对数据库做“分库分表”,在实现上有三种策略:垂直拆分、水平拆分、垂直水平拆分分库分表的整体设计方案......
  • shell使用-基本正则和常用例子
    元字符描述\将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\\n”匹配\n。“\n”匹配换行符。序列“\\”匹配“\”而“\(”则匹配“(”。......
  • LeetCode 15. 三数之和
    classSolution{public:vector<vector<int>>threeSum(vector<int>&nums){vector<vector<int>>res;sort(nums.begin(),nums.end());......
  • Amazon Cloud Technology China Summit
    2022.10.13在本次为期2天的峰会上,亚马逊云科技发布了云计算技术趋势展望,宣布“连中外、襄百业、携伙伴、促绿色”四大战略举措,进一步利用亚马逊云科技全球优势和资源,更好......
  • Linux文本编辑工具Vim的常用快捷键
    Vim的三种常用模式及常用快捷键Vim有三种模式:一般模式、编辑模式和命令行模式一般模式移动光标按键作用b或者向左的方向键光标向左移动一个字符l或者向右......
  • Python+ChatGPT制作一个AI实用百宝箱
    ChatGPT最近在互联网掀起了一阵热潮,其高度智能化的功能能够给我们现实生活带来诸多的便利,可以帮助你写文章、写报告、写周报、做表格、做策划甚至还会写代码。只要与文字......
  • 笔试算法《字符串排序_1》
    题目描述编写一个程序,将输入字符串中的字符按如下规则排序。规则1:英文字母从A到Z排列,不区分大小写。如,输入:Type输出:epTy规则2:同一个英文字母的大小写同时存在时,......
  • scanf的原理
    //1、scanf来读取输入数据时会阻塞,因为标准缓冲区为空。//2、scanf用来读取标准输入,scnaf把标准输入内的内容,需要放到某个变量空间里,因此变量必须取地址。/*3、scanf在读取......