mysql的binlog日誌是維繫mysql主從同步的重要媒介。binlog日誌對SQL記錄策略,直接影響到主從之間的數據一致性。接下來咱們來實驗下,看看mysql對事務表和非事務表的DML操做,binlog是如何記錄的。
mysql
實驗環境:mysql官方社區版5.7.18, 操做系統centos7.3,binlog日誌格式採用row格式。sql
一、建立Myisam表b和Innodb表a。
centos
CREATE TABLE `a` ( `id` int(11) NOT NULL, `name` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;安全
CREATE TABLE `b` ( `id` int(11) DEFAULT NULL, `name` varchar(10) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8;session
能夠看出,兩個表結構都是同樣的,除了引擎不一樣。
app
二、根據GTID是否開啓,分爲2大類:
ide
(1.1)關閉GTID,顯式開啓事務並提交事務。this
執行的DML操做以下: root@localhost:mysql3306.sock 16:28: [test]>begin; Query OK, 0 rows affected (0.00 sec) root@localhost:mysql3306.sock 16:28: [test]>insert into a values (1,"x"); Query OK, 1 row affected (0.00 sec) root@localhost:mysql3306.sock 16:29: [test]>insert into b values (1,"x"); Query OK, 1 row affected (0.00 sec) root@localhost:mysql3306.sock 16:29: [test]>commit; Query OK, 0 rows affected (0.00 sec) 生成的相應binlog日誌以下: [root@mysql3 binlog]# mysqlbinlog -vv mysql-bin.000001 --base64-output=decode-rows /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #180122 16:28:29 server id 43306 end_log_pos 123 CRC32 0x37c1a2aa Start: binlog v 4, server v 5.7.18-log created 180122 16:28:29 at startup # Warning: this binlog is either in use or was not closed properly. ROLLBACK/*!*/; # at 123 #180122 16:28:29 server id 43306 end_log_pos 154 CRC32 0x52be72b2 Previous-GTIDs # [empty] # at 154 #180122 16:29:03 server id 43306 end_log_pos 219 CRC32 0x0769b732 Anonymous_GTID last_committed=0 sequence_number=1 SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 219 #180122 16:29:03 server id 43306 end_log_pos 291 CRC32 0x0e3a8a35 Query thread_id=4 exec_time=0 error_code=0 SET TIMESTAMP=1516609743/*!*/; SET @@session.pseudo_thread_id=4/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=2097152/*!*/; 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/*!*/; BEGIN /*!*/; # at 291 #180122 16:29:03 server id 43306 end_log_pos 338 CRC32 0xfe6cd337 Table_map: `test`.`b` mapped to number 222 # at 338 #180122 16:29:03 server id 43306 end_log_pos 380 CRC32 0x0d64e0a4 Write_rows: table id 222 flags: STMT_END_F ### INSERT INTO `test`.`b` ### SET ### @1=1 /* INT meta=0 nullable=1 is_null=0 */ ### @2='x' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */ # at 380 #180122 16:29:03 server id 43306 end_log_pos 453 CRC32 0xd4cc34e1 Query thread_id=4 exec_time=0 error_code=0 SET TIMESTAMP=1516609743/*!*/; COMMIT /*!*/; # at 453 #180122 16:29:05 server id 43306 end_log_pos 518 CRC32 0xeec8cb53 Anonymous_GTID last_committed=1 sequence_number=2 SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 518 #180122 16:29:00 server id 43306 end_log_pos 590 CRC32 0xb472a7d3 Query thread_id=4 exec_time=0 error_code=0 SET TIMESTAMP=1516609740/*!*/; BEGIN /*!*/; # at 590 #180122 16:29:00 server id 43306 end_log_pos 637 CRC32 0xe848c910 Table_map: `test`.`a` mapped to number 221 # at 637 #180122 16:29:00 server id 43306 end_log_pos 679 CRC32 0xec326782 Write_rows: table id 221 flags: STMT_END_F ### INSERT INTO `test`.`a` ### SET ### @1=1 /* INT meta=0 nullable=0 is_null=0 */ ### @2='x' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */ # at 679 #180122 16:29:05 server id 43306 end_log_pos 710 CRC32 0x5b9b8331 Xid = 58 COMMIT/*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
從生成的binlog來看,無論是Myisam仍是Innodb引擎,都生成相應的binlog日誌。centos7
(1.2)關閉GTID,顯式開啓事務並回滾事務操作系統
執行的DML操做以下: root@localhost:mysql3306.sock 16:29: [test]>flush logs; Query OK, 0 rows affected (0.01 sec) root@localhost:mysql3306.sock 16:35: [test]>begin; Query OK, 0 rows affected (0.01 sec) root@localhost:mysql3306.sock 16:35: [test]>insert into a values (2,"x"); Query OK, 1 row affected (0.00 sec) root@localhost:mysql3306.sock 16:36: [test]>insert into b values (2,"x"); Query OK, 1 row affected (0.00 sec) root@localhost:mysql3306.sock 16:36: [test]>rollback; Query OK, 0 rows affected, 1 warning (0.01 sec) 當前表的數據以下: root@localhost:mysql3306.sock 16:36: [test]>select * from a; +----+------+ | id | name | +----+------+ | 1 | x | +----+------+ 1 row in set (0.00 sec) root@localhost:mysql3306.sock 16:37: [test]>select * from b; +------+------+ | id | name | +------+------+ | 1 | x | | 2 | x | +------+------+ 2 rows in set (0.00 sec) 生成的相應binlog日誌以下: [root@mysql3 binlog]# mysqlbinlog -vv mysql-bin.000002 --base64-output=decode-rows /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #180122 16:35:39 server id 43306 end_log_pos 123 CRC32 0xed4918d4 Start: binlog v 4, server v 5.7.18-log created 180122 16:35:39 # Warning: this binlog is either in use or was not closed properly. # at 123 #180122 16:35:39 server id 43306 end_log_pos 154 CRC32 0x25a5629b Previous-GTIDs # [empty] # at 154 #180122 16:36:11 server id 43306 end_log_pos 219 CRC32 0xe56a83ea Anonymous_GTID last_committed=0 sequence_number=1 SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 219 #180122 16:36:11 server id 43306 end_log_pos 291 CRC32 0x322b71cf Query thread_id=4 exec_time=0 error_code=0 SET TIMESTAMP=1516610171/*!*/; SET @@session.pseudo_thread_id=4/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=2097152/*!*/; 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/*!*/; BEGIN /*!*/; # at 291 #180122 16:36:11 server id 43306 end_log_pos 338 CRC32 0xd5964b6b Table_map: `test`.`b` mapped to number 222 # at 338 #180122 16:36:11 server id 43306 end_log_pos 380 CRC32 0xa2b7dc67 Write_rows: table id 222 flags: STMT_END_F ### INSERT INTO `test`.`b` ### SET ### @1=2 /* INT meta=0 nullable=1 is_null=0 */ ### @2='x' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */ # at 380 #180122 16:36:11 server id 43306 end_log_pos 453 CRC32 0x89983e18 Query thread_id=4 exec_time=0 error_code=0 SET TIMESTAMP=1516610171/*!*/; COMMIT /*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
從生成的binlog可知,表a回滾了數據,而表b因爲是非事務表的緣故,沒有回滾數據。同時表b的數據變動也生成對應的binlog日誌。而表a因爲事務回滾的緣故,沒有變動數據,也沒有生成binlog。
(2.1)開啓GTID,顯式開啓事務並提交事務。
執行的DML操做以下: root@localhost:mysql3306.sock 16:44: [test]>begin; Query OK, 0 rows affected (0.00 sec) root@localhost:mysql3306.sock 16:44: [test]>insert into a values (3,"x"); Query OK, 1 row affected (0.02 sec) root@localhost:mysql3306.sock 16:44: [test]>insert into b values (3,"x"); ERROR 1785 (HY000): Statement violates GTID consistency: Updates to non-transactional tables can only be done in either autocommitted statements or single-statement transactions, and never in the same statement as updates to transactional tables. root@localhost:mysql3306.sock 16:44: [test]>commit; Query OK, 0 rows affected (0.01 sec)
從報錯信息可知,在開啓GTID模式下,非事務表的DML操做只能在autocommitted statements和single-statement transactions狀況下執行,在一個顯式事務中混合事務表和非事務表的DML操做是不被容許的。
生成的相應binlog日誌以下: [root@mysql3 binlog]# mysqlbinlog -vv mysql-bin.000001 --base64-output=decode-rows /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #180122 16:44:07 server id 43306 end_log_pos 123 CRC32 0xf53a5a98 Start: binlog v 4, server v 5.7.18-log created 180122 16:44:07 at startup # Warning: this binlog is either in use or was not closed properly. ROLLBACK/*!*/; # at 123 #180122 16:44:07 server id 43306 end_log_pos 154 CRC32 0xb9b802e5 Previous-GTIDs # [empty] # at 154 #180122 16:44:47 server id 43306 end_log_pos 219 CRC32 0x716ab799 GTID last_committed=0 sequence_number=1 SET @@SESSION.GTID_NEXT= '5252f852-685e-11e7-8eeb-000c299fe44c:1'/*!*/; # at 219 #180122 16:44:32 server id 43306 end_log_pos 291 CRC32 0x816f8092 Query thread_id=3 exec_time=0 error_code=0 SET TIMESTAMP=1516610672/*!*/; SET @@session.pseudo_thread_id=3/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=2097152/*!*/; 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/*!*/; BEGIN /*!*/; # at 291 #180122 16:44:32 server id 43306 end_log_pos 338 CRC32 0x9f700cb0 Table_map: `test`.`a` mapped to number 219 # at 338 #180122 16:44:32 server id 43306 end_log_pos 380 CRC32 0x192a0649 Write_rows: table id 219 flags: STMT_END_F ### INSERT INTO `test`.`a` ### SET ### @1=3 /* INT meta=0 nullable=0 is_null=0 */ ### @2='x' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */ # at 380 #180122 16:44:47 server id 43306 end_log_pos 411 CRC32 0x1ef809c7 Xid = 7 COMMIT/*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
從生成的binlog可知,只生成了表a的DML變動記錄。
(2.2)開啓GTID,顯式開啓事務並回滾事務。
執行的DML操做以下: root@localhost:mysql3306.sock 16:52: [test]>flush logs; Query OK, 0 rows affected (0.01 sec) root@localhost:mysql3306.sock 16:52: [test]>begin; Query OK, 0 rows affected (0.00 sec) root@localhost:mysql3306.sock 16:52: [test]>insert into a values (4,"x"); Query OK, 1 row affected (0.00 sec) root@localhost:mysql3306.sock 16:52: [test]>insert into b values (4,"x"); ERROR 1785 (HY000): Statement violates GTID consistency: Updates to non-transactional tables can only be done in either autocommitted statements or single-statement transactions, and never in the same statement as updates to transactional tables. root@localhost:mysql3306.sock 16:52: [test]>rollback; Query OK, 0 rows affected (0.08 sec) root@localhost:mysql3306.sock 16:52: [test]>select * from a; +----+------+ | id | name | +----+------+ | 1 | x | | 3 | x | +----+------+ 2 rows in set (0.00 sec) root@localhost:mysql3306.sock 16:54: [test]>select * from b; +------+------+ | id | name | +------+------+ | 1 | x | | 2 | x | +------+------+ 2 rows in set (0.00 sec)
從報錯信息可知,在開啓GTID模式下,非事務表的DML操做只能在autocommitted statements和single-statement transactions狀況下執行,在一個顯式事務中混合事務表和非事務表的DML操做是不被容許的。表a和表b都沒有數據變動。
生成的相應binlog日誌以下: [root@mysql3 binlog]# mysqlbinlog -vv mysql-bin.000002 --base64-output=decode-rows /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #180122 16:52:16 server id 43306 end_log_pos 123 CRC32 0x946808ab Start: binlog v 4, server v 5.7.18-log created 180122 16:52:16 # Warning: this binlog is either in use or was not closed properly. # at 123 #180122 16:52:16 server id 43306 end_log_pos 194 CRC32 0x7c37ab8f Previous-GTIDs # 5252f852-685e-11e7-8eeb-000c299fe44c:1 SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
從生成的binlog可知,也沒有生成對應的變動記錄。
綜上所述,在mysql未開啓GTID模式下,顯式執行的事務中若是包含了非事務表的DML,這些表的數據並不會回滾(非事務性表無回滾的概念),同時也會爲了主從數據一致的緣故,生成對應的binlog日誌。而開啓GTID模式下,非事務表只能在autocommit=1模式下單獨執行或者只包含單個SQL的事務裏執行。可見,開啓GTID模式,經過禁止非事務表混入顯式事務的方式去更好的保證了事務ACID特性,這種方式更爲安全。